hibernate/hibernate-orm · error · MappingException

Two different subclasses of '" + getEntityName() + "' map to

Error message

Two different subclasses of '" + getEntityName() + "' map to the table '" + table.getName() + "' and the hierarchy has no discriminator column

What it means

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).

Source

Thrown at hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java:315

	 * the subclasses are assumed to occupy distinct tables, and it's an error to map
	 * two subclasses to the same table.
	 * <p>
	 * As a special exception to this, if a joined inheritance hierarchy defines an
	 * explicit {@link jakarta.persistence.DiscriminatorColumn}, we tolerate table
	 * duplication among the subclasses, but we must "force" the discriminator to
	 * account for this. (See issue HHH-14526.)
	 */
	private void checkTableDuplication() {
		if ( hasSubclasses() ) {
			final Set<Table> tables = new HashSet<>();
			tables.add( getTable() );
			for ( var subclass : getSubclasses() ) {
				if ( !(subclass instanceof SingleTableSubclass) ) {
					final var table = subclass.getTable();
					if ( !tables.add( table ) ) {
						// we encountered a duplicate table mapping
						if ( getDiscriminator() == null ) {
							throw new MappingException( "Two different subclasses of '" + getEntityName()
									+ "' map to the table '" + table.getName()
									+ "' and the hierarchy has no discriminator column" );
						}
						else {
							// This is arguably not the right place to do this.
							// Perhaps it's an issue better dealt with later on
							// by the persisters. See HHH-14526.
							forceDiscriminator = true;
						}
						break;
					}
				}
			}
		}
	}

	/**
	 * Composite id classes are supposed to override {@link #equals} and

View on GitHub (pinned to fad1729dce)

Solutions

  1. Add a discriminator column to the root (@DiscriminatorColumn or a discriminator element) so Hibernate can tell rows apart
  2. Give each subclass its own table if their data really differs
  3. If all subclasses intentionally share the root table, use single-table inheritance instead of JOINED

Example fix

// before
@Entity @Inheritance(strategy = InheritanceType.JOINED)
class Payment {}
@Entity @Table(name = "tx") class CardPayment extends Payment {}
@Entity @Table(name = "tx") class CashPayment extends Payment {}

// after
@Entity @Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "ptype")
class Payment {}
@Entity @Table(name = "tx") class CardPayment extends Payment {}
@Entity @Table(name = "tx") class CashPayment extends Payment {}
Defensive patterns

Strategy: validation

Validate before calling

Set<Table> tables = new HashSet<>();
tables.add(root.getTable());
for (PersistentClass sub : root.getSubclasses()) {
    if (!(sub instanceof org.hibernate.mapping.SingleTableSubclass)
            && !tables.add(sub.getTable())
            && root.getDiscriminator() == null) {
        // two subclasses share a table with no discriminator; fix the hierarchy first
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: Refactoring two similar subclasses onto one table without adding @DiscriminatorColumn; consolidating tables in single-table-like designs while keeping JOINED inheritance.

Related errors


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