{"record":{"id":"3b70307aaefd2bee","repo":"hibernate/hibernate-orm","slug":"root-entity-entityname-is-annotated-discrimi","errorCode":null,"errorMessage":"Root entity '<entityName>' is annotated '@DiscriminatorOptions' but has no discriminator column","messagePattern":"Root entity '<entityName>' is annotated '@DiscriminatorOptions' but has no discriminator column","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/binder/internal/DiscriminatorOptionsBinder.java","lineNumber":27,"sourceCode":"import org.hibernate.binder.TypeBinder;\nimport org.hibernate.boot.spi.MetadataBuildingContext;\nimport org.hibernate.mapping.Component;\nimport org.hibernate.mapping.PersistentClass;\nimport org.hibernate.mapping.RootClass;\n\n/**\n * Handles {@link DiscriminatorOptions} annotations.\n *\n * @author Gavin King\n *\n * @since 6.5\n */\npublic class DiscriminatorOptionsBinder implements TypeBinder<DiscriminatorOptions> {\n\t@Override\n\tpublic void bind(DiscriminatorOptions options, MetadataBuildingContext context, PersistentClass persistentClass) {\n\t\tif ( persistentClass instanceof RootClass rootClass ) {\n\t\t\tif ( !rootClass.hasDiscriminator() ) {\n\t\t\t\tthrow new AnnotationException( \"Root entity '\" + rootClass.getEntityName()\n\t\t\t\t\t\t+ \"' is annotated '@DiscriminatorOptions' but has no discriminator column\" );\n\t\t\t}\n\t\t\trootClass.setForceDiscriminator( options.force() );\n\t\t\trootClass.setDiscriminatorInsertable( options.insert() );\n\t\t}\n\t\telse {\n\t\t\tthrow new AnnotationException(\"Class '\" + persistentClass.getClassName()\n\t\t\t\t\t+ \"' is not the root class of an entity inheritance hierarchy and may not be annotated '@DiscriminatorOptions'\");\n\t\t}\n\t}\n\n\t@Override\n\tpublic void bind(DiscriminatorOptions options, MetadataBuildingContext context, Component embeddableClass) {\n\t\tthrow new AnnotationException(\"Class '\" + embeddableClass.getComponentClassName()\n\t\t\t\t+ \"' is an '@Embeddable' type and may not be annotated '@DiscriminatorOptions'\");\n\t}\n}\n","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/binder/internal/DiscriminatorOptionsBinder.java#L9-L45","documentation":"@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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n@Entity\n@Inheritance(strategy = InheritanceType.JOINED)\n@DiscriminatorOptions(force = true)\npublic abstract class BillingDetails { ... }\n\n// after\n@Entity\n@Inheritance(strategy = InheritanceType.JOINED)\n@DiscriminatorColumn(name = \"billing_type\")\n@DiscriminatorOptions(force = true)\npublic abstract class BillingDetails { ... }","handlingStrategy":"validation","validationCode":"if (cls.isAnnotationPresent(org.hibernate.annotations.DiscriminatorOptions.class)\n        && cls.isAnnotationPresent(jakarta.persistence.Inheritance.class)\n        && !cls.isAnnotationPresent(jakarta.persistence.DiscriminatorColumn.class)) {\n    // JOINED / TABLE_PER_CLASS have no implicit discriminator column\n    throw new IllegalStateException(\"@DiscriminatorOptions without @DiscriminatorColumn on \" + cls.getName());\n}","typeGuard":null,"tryCatchPattern":"Catch org.hibernate.AnnotationException during bootstrap and report the entity name; fail fast.","preventionTips":["Always pair @DiscriminatorOptions with @DiscriminatorColumn.","Re-check inheritance annotations after changing the inheritance strategy.","Keep inheritance settings centralized on the root entity."],"tags":["hibernate","jpa","annotations","inheritance","discriminator","orm-mapping"],"backgroundTag":"jpa-annotation-misplacement","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}