{"record":{"id":"193961bb8596bb80","repo":"hibernate/hibernate-orm","slug":"two-different-subclasses-of-getentityname","errorCode":null,"errorMessage":"Two different subclasses of '\" + getEntityName() + \"' map to the table '\" + table.getName() + \"' and the hierarchy has no discriminator column","messagePattern":"Two different subclasses of '\" \\+ getEntityName\\(\\) \\+ \"' map to the table '\" \\+ table\\.getName\\(\\) \\+ \"' and the hierarchy has no discriminator column","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java","lineNumber":315,"sourceCode":"\t * the subclasses are assumed to occupy distinct tables, and it's an error to map\n\t * two subclasses to the same table.\n\t * <p>\n\t * As a special exception to this, if a joined inheritance hierarchy defines an\n\t * explicit {@link jakarta.persistence.DiscriminatorColumn}, we tolerate table\n\t * duplication among the subclasses, but we must \"force\" the discriminator to\n\t * account for this. (See issue HHH-14526.)\n\t */\n\tprivate void checkTableDuplication() {\n\t\tif ( hasSubclasses() ) {\n\t\t\tfinal Set<Table> tables = new HashSet<>();\n\t\t\ttables.add( getTable() );\n\t\t\tfor ( var subclass : getSubclasses() ) {\n\t\t\t\tif ( !(subclass instanceof SingleTableSubclass) ) {\n\t\t\t\t\tfinal var table = subclass.getTable();\n\t\t\t\t\tif ( !tables.add( table ) ) {\n\t\t\t\t\t\t// we encountered a duplicate table mapping\n\t\t\t\t\t\tif ( getDiscriminator() == null ) {\n\t\t\t\t\t\t\tthrow new MappingException( \"Two different subclasses of '\" + getEntityName()\n\t\t\t\t\t\t\t\t\t+ \"' map to the table '\" + table.getName()\n\t\t\t\t\t\t\t\t\t+ \"' and the hierarchy has no discriminator column\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// This is arguably not the right place to do this.\n\t\t\t\t\t\t\t// Perhaps it's an issue better dealt with later on\n\t\t\t\t\t\t\t// by the persisters. See HHH-14526.\n\t\t\t\t\t\t\tforceDiscriminator = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Composite id classes are supposed to override {@link #equals} and","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java#L297-L333","documentation":"Two non-single-table subclasses of the same root are mapped to the same database table while the hierarchy has no discriminator column. checkTableDuplication() collects the tables of the root and its subclasses; on a duplicate with getDiscriminator() == null it rejects the mapping, because rows of the two classes would be indistinguishable. With a discriminator present it instead forces discriminator use (see HHH-14526).","triggerScenarios":"JOINED inheritance where two sibling @Entity subclasses declare the same @Table(name); union-subclass style mappings sharing a table; copy-pasted subclass mappings that forgot to change the table name.","commonSituations":"Refactoring two similar subclasses onto one table without adding @DiscriminatorColumn; consolidating tables in single-table-like designs while keeping JOINED inheritance.","solutions":["Add a discriminator column to the root (@DiscriminatorColumn or a discriminator element) so Hibernate can tell rows apart","Give each subclass its own table if their data really differs","If all subclasses intentionally share the root table, use single-table inheritance instead of JOINED"],"exampleFix":"// before\n@Entity @Inheritance(strategy = InheritanceType.JOINED)\nclass Payment {}\n@Entity @Table(name = \"tx\") class CardPayment extends Payment {}\n@Entity @Table(name = \"tx\") class CashPayment extends Payment {}\n\n// after\n@Entity @Inheritance(strategy = InheritanceType.JOINED)\n@DiscriminatorColumn(name = \"ptype\")\nclass Payment {}\n@Entity @Table(name = \"tx\") class CardPayment extends Payment {}\n@Entity @Table(name = \"tx\") class CashPayment extends Payment {}","handlingStrategy":"validation","validationCode":"Set<Table> tables = new HashSet<>();\ntables.add(root.getTable());\nfor (PersistentClass sub : root.getSubclasses()) {\n    if (!(sub instanceof org.hibernate.mapping.SingleTableSubclass)\n            && !tables.add(sub.getTable())\n            && root.getDiscriminator() == null) {\n        // two subclasses share a table with no discriminator; fix the hierarchy first\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Model shared-table hierarchies as SINGLE_TABLE with @DiscriminatorColumn on the root","When two JOINED subclasses must share a table, add a discriminator column to the root","Give subclasses distinct tables unless sharing is deliberate"],"tags":["hibernate","orm","inheritance","mapping-validation","discriminator"],"backgroundTag":"table-mapping-conflict","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}