hibernate/hibernate-orm · error · AnnotationException
Root entity '<entityName>' is annotated '@DiscriminatorOptio
Error message
Root entity '<entityName>' is annotated '@DiscriminatorOptions' but has no discriminator column
What it means
@DiscriminatorOptions(force/insert) tunes how the discriminator column is used in queries and inserts — meaningful only when the hierarchy actually has one. DiscriminatorOptionsBinder checks RootClass.hasDiscriminator(); with JOINED or TABLE_PER_CLASS inheritance and no explicit @DiscriminatorColumn it is false, so binding the root throws an AnnotationException. SINGLE_TABLE hierarchies get a discriminator by default and do not trigger this.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/binder/internal/DiscriminatorOptionsBinder.java:27
import org.hibernate.binder.TypeBinder;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
/**
* Handles {@link DiscriminatorOptions} annotations.
*
* @author Gavin King
*
* @since 6.5
*/
public class DiscriminatorOptionsBinder implements TypeBinder<DiscriminatorOptions> {
@Override
public void bind(DiscriminatorOptions options, MetadataBuildingContext context, PersistentClass persistentClass) {
if ( persistentClass instanceof RootClass rootClass ) {
if ( !rootClass.hasDiscriminator() ) {
throw new AnnotationException( "Root entity '" + rootClass.getEntityName()
+ "' is annotated '@DiscriminatorOptions' but has no discriminator column" );
}
rootClass.setForceDiscriminator( options.force() );
rootClass.setDiscriminatorInsertable( options.insert() );
}
else {
throw new AnnotationException("Class '" + persistentClass.getClassName()
+ "' is not the root class of an entity inheritance hierarchy and may not be annotated '@DiscriminatorOptions'");
}
}
@Override
public void bind(DiscriminatorOptions options, MetadataBuildingContext context, Component embeddableClass) {
throw new AnnotationException("Class '" + embeddableClass.getComponentClassName()
+ "' is an '@Embeddable' type and may not be annotated '@DiscriminatorOptions'");
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Add @DiscriminatorColumn to the root entity so the JOINED hierarchy stores an explicit discriminator column.
- Or remove @DiscriminatorOptions if force/insert semantics are not needed.
- If you relied on force=true for polymorphic queries, note JOINED inheritance unions subtype tables instead of using a discriminator.
Example fix
// before
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorOptions(force = true)
public abstract class BillingDetails { ... }
// after
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "billing_type")
@DiscriminatorOptions(force = true)
public abstract class BillingDetails { ... } Defensive patterns
Strategy: validation
Validate before calling
if (cls.isAnnotationPresent(org.hibernate.annotations.DiscriminatorOptions.class)
&& cls.isAnnotationPresent(jakarta.persistence.Inheritance.class)
&& !cls.isAnnotationPresent(jakarta.persistence.DiscriminatorColumn.class)) {
// JOINED / TABLE_PER_CLASS have no implicit discriminator column
throw new IllegalStateException("@DiscriminatorOptions without @DiscriminatorColumn on " + cls.getName());
} Try / catch
Catch org.hibernate.AnnotationException during bootstrap and report the entity name; fail fast.
Prevention
- Always pair @DiscriminatorOptions with @DiscriminatorColumn.
- Re-check inheritance annotations after changing the inheritance strategy.
- Keep inheritance settings centralized on the root entity.
When it happens
Trigger: A root entity with @Inheritance(strategy = JOINED) (or TABLE_PER_CLASS/UNION) annotated @DiscriminatorOptions but without @DiscriminatorColumn; SessionFactory bootstrap binds the type-level annotation and throws.
Common situations: Switching a hierarchy from SINGLE_TABLE to JOINED and keeping @DiscriminatorOptions behind; adding the annotation as 'documentation'; hbm.xml-to-annotation migration where the discriminator element was dropped.
Related errors
- Class '<className>' is not the root class of an entity inher
- Class '<componentClassName>' is an '@Embeddable' type and ma
- Class '<componentClassName>' is an '@Embeddable' type and ma
- Property '<propertyName>' may not be annotated '@BatchSize'
- One to many association '<propertyName>' was annotated '@Col
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/3b70307aaefd2bee.
Report an issue: GitHub.