hibernate/hibernate-orm · error · HibernateException

Cannot interpret discriminator value ({discriminatorRole}) :

Error message

Cannot interpret discriminator value ({discriminatorRole}) : {discriminatorValue}

What it means

Thrown by FullNameImplicitDiscriminatorStrategy.toEntityMapping when a discriminator value read from data cannot be translated into a mapped EntityMappingType. This strategy (used for inheritance mappings without an explicit discriminator, where the discriminator is effectively the entity name) accepts only String values that resolve via mappingModel.findEntityDescriptor(...); anything else - a non-String value, an unregistered name, wrong casing, qualified vs. unqualified mismatch - fails with this HibernateException echoing the discriminator role and the offending value.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/metamodel/internal/FullNameImplicitDiscriminatorStrategy.java:35

 */
public class FullNameImplicitDiscriminatorStrategy implements ImplicitDiscriminatorStrategy {
	public static final FullNameImplicitDiscriminatorStrategy FULL_NAME_STRATEGY = new FullNameImplicitDiscriminatorStrategy();

	@Override
	public Object toDiscriminatorValue(EntityMappingType entityMapping, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
		return entityMapping.getEntityName();
	}

	@Override
	public EntityMappingType toEntityMapping(Object discriminatorValue, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
		if ( discriminatorValue instanceof String assumedEntityName ) {
			final var persister = mappingModel.findEntityDescriptor( assumedEntityName );
			if ( persister != null ) {
				return persister;
			}
		}

		throw new HibernateException( "Cannot interpret discriminator value (" + discriminatorRole + ") : " + discriminatorValue );
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Compare the value printed in the message with the registered entity names (sessionFactory.getMetamodel().getEntityNames() or entity descriptors)
  2. Migrate the stored discriminator values to match the current entity names (UPDATE ... or a startup fixer script)
  3. If the value is legitimately not an entity name, switch the mapping to an explicit @DiscriminatorColumn/@DiscriminatorValue scheme instead of the implicit full-name strategy
  4. Keep entity names stable across refactors by explicitly naming entities (@Entity(name=...)) so renames do not change discriminator data

Example fix

// before - entity renamed, old rows keep the old name
@Entity(name = "BillingDoc")            // rows still store 'BillingDocument'
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BillingDocument { ... }

// after - pin a stable entity name
@Entity(name = "BillingDocument")       // matches stored discriminator data
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BillingDocument { ... }

// or migrate the data
-- UPDATE docs SET dtype = 'BillingDoc' WHERE dtype = 'BillingDocument';
Defensive patterns

Strategy: validation

Validate before calling

// Startup check: every stored discriminator value must resolve to a mapped entity
Set<String> registered = emf.getMetamodel().getEntities().stream().map(EntityType::getName).collect(toSet());
for ( String stored : jdbc.queryForList("SELECT DISTINCT dtype FROM docs", String.class) ) {
    if ( !registered.contains(stored) ) {
        throw new IllegalStateException("Unmapped discriminator value in data: '" + stored + "'");
    }
}

Type guard

static boolean isKnownEntityName(Metamodel mm, Object discriminatorValue) {
    if (!(discriminatorValue instanceof String name)) return false;
    try { mm.entity(name); return true; } catch (IllegalArgumentException e) { return false; }
}

Try / catch

try {
    return em.createQuery("select d from BillingDocument d", BillingDocument.class).getResultList();
}
catch ( org.hibernate.HibernateException e ) {
    if ( e.getMessage() != null && e.getMessage().contains("Cannot interpret discriminator value") ) {
        throw new DataMigrationNeeded("Stored discriminator no longer matches mapped entity names: " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Reading inheritance-hierarchy rows whose discriminator/name column contains a value that is not a currently mapped entity name (entity renamed or moved packages between releases, legacy data, manually inserted rows); discriminator stored fully-qualified while mapping registers short names or vice versa; enum/native integer values left in a column the implicit strategy treats as entity names.

Common situations: Refactoring entity class names or packages after go-live without a data migration; environments restored from old backups into new schemas; queries over polymorphic hierarchies (table-per-class / implicit polymorphism) hitting stale discriminator data.

Related errors


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