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
- Compare the value printed in the message with the registered entity names (sessionFactory.getMetamodel().getEntityNames() or entity descriptors)
- Migrate the stored discriminator values to match the current entity names (UPDATE ... or a startup fixer script)
- 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
- 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
- Pin stable entity names with @Entity(name = "...") so class/package refactors never touch stored data
- Add data-migration updates whenever renaming entities in polymorphic hierarchies
- Include a discriminator-value audit in migration checklists and CI datasets
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
- Expected object of type `%s`, but found `%s`; discriminator
- Root entity '<entityName>' is annotated '@DiscriminatorOptio
- Class '<className>' is not the root class of an entity inher
- Discriminator column mapping given for non-discriminated ent
- Two different subclasses of '" + getEntityName() + "' map to
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/661a3b8c2aa818af.
Report an issue: GitHub.