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

  1. Add @DiscriminatorColumn to the root entity so the JOINED hierarchy stores an explicit discriminator column.
  2. Or remove @DiscriminatorOptions if force/insert semantics are not needed.
  3. 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

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


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/3b70307aaefd2bee. Report an issue: GitHub.