ErrLookup › Background articles › Hibernate MappingException: mapping errors that fail SessionFactory/EntityManagerFactory startup, explained
Hibernate MappingException: mapping errors that fail SessionFactory/EntityManagerFactory startup, explained
MappingException is the exception Hibernate ORM throws when the object-relational mapping itself is invalid, almost always while the SessionFactory or EntityManagerFactory is built, before any query runs. Developers meet it as a bootstrap crash naming an entity, property, or dialect: an embeddable mapped twice with different attributes, IDENTITY or SEQUENCE generation on a database that lacks it, contradictory annotations like @OptimisticLock(ALL) without @DynamicUpdate, malformed native-query result mappings, or legacy hbm.xml corners. This article covers the whole family, what each sub-group means, and the fixes that hold across it.
Distilled from 255 documented records across 2 repositories.
Background
MappingException (org.hibernate.mapping.MappingException) is the persistence layer's mapping-validation failure. When Hibernate builds its metadata model from annotations and hbm.xml files, the binders, persister constructors, and JPA metamodel population code validate every mapping decision before the factory opens. The documented records in this family fire almost exclusively during that build: the application crashes at SessionFactory/EntityManagerFactory creation with a stack trace pointing into the binding code, and the message usually names the offending entity, property, query, or dialect class, so the failed deployment itself is the diagnostic.
The class exists to fail fast. Instead of emitting wrong SQL at runtime, Hibernate rejects mappings it knows cannot work: a @ManyToOne cascade='delete-orphan' that is not a logical one-to-one, a @NaturalId association whose @NotFound(IGNORE) would silently break natural-id resolution, an entity whose OptimisticLockType.ALL/DIRTY column-comparison locking needs dynamic UPDATE SQL that was never enabled. Several checks are deliberately structural rather than data-driven, which is why the exception carries entity and property names rather than row values.
A large sub-family is dialect capability negotiation. Hibernate asks the active dialect for the SQL fragments a mapping implies, and the default support objects throw MappingException when the database lacks the feature: getIdentitySelectString on dialects without identity support, NoSequenceSupport.getSequenceNextValString on MySQL or DB2 for i, the native temporal exclusion column option on every TemporalTableSupport except MariaDB's, non-integer identity columns on CockroachDB, and identity-select retrieval on Spanner. Timing inside this sub-group is library- and configuration-specific: most of these fire at bootstrap while the mapping is bound, but a sequence-generator failure can also surface at the first insert that needs an id.
The rest of the family clusters around three areas: native-query result-set mapping (an hbm.xml <sql-query> with no SQL body, resultset-ref combined with inline returns, a <return-collection/> mixed with entity returns, @FieldResult dotted paths that cross a basic attribute), legacy hbm.xml corners (an <id> with no property under JPA metamodel population, unsaved-value='negative' on non-numeric versions, dynamic-map entities whose properties lack explicit types, <many-to-any> with fewer than two columns), and version-upgrade semantics such as the Hibernate 6.2 change in Byte[]/Character[] wrapper-array handling. All 30 best-documented records of the family come from the hibernate/hibernate-orm repository, so the behaviors above are grounded in that codebase; where the same exception class appears in other repositories, its meaning is library-specific and should be checked against that library's own records.
Common causes
- Association or column reference Hibernate cannot resolve.A @ManyToOne/@OneToOne points at a class that is not a registered entity, a targetEntity/class/property-ref name is stale after a refactor, or referencedColumnName supplies the physical column name instead of the logical one the mapping registered. The exception names the referenced entity and attribute so you can trace the broken association.
- Key-generation or feature request the dialect cannot satisfy.IDENTITY generation on a dialect whose IdentityColumnSupport throws, SEQUENCE on MySQL/DB2 for i (NoSequenceSupport), non-integer identity columns on CockroachDB, identity-select retrieval on Spanner, or @Excluded with the NATIVE temporal-table strategy on a dialect without native temporal tables. Some of these surface at first insert rather than bootstrap.
- Contradictory annotations on one entity.@OptimisticLock(ALL/DIRTY) without @DynamicUpdate, or combined with a @Version field; @NaturalId on an association that also carries @NotFound(IGNORE), including nested inside an embeddable; @Proxy(proxyClass=...) naming a concrete class instead of an interface.
- Discriminator misconfiguration.A @DiscriminatorValue literal that cannot be parsed as the declared @DiscriminatorColumn type (e.g. 'GUEST' on INTEGER), @DiscriminatorFormula on a JOINED hierarchy, custom discriminator types whose JdbcLiteralFormatter rejects the value, or a discriminator column alias mapped for an entity with no discriminator.
- Malformed native-query result mappings.An hbm.xml <sql-query> with no SQL text, resultset-ref plus inline <return> elements in the same query, a <return-collection/> combined with entity or scalar returns, collection return-property paths that skip the key/element/index part, or @FieldResult paths whose dotted intermediate segments are basic attributes.
- Legacy hbm.xml corners.An <id> with no name under JPA metamodel population, unsaved-value='negative' on a non-numeric version, dynamic-map (entity-name) properties without explicit type attributes, <many-to-any> with fewer than two columns, @CollectionId with an identity/native generator, or delete-orphan cascade on a many-to-one that is not unique.
- Mapping drift after refactoring or upgrade.The same embeddable class reused across mappings with different attribute lists (different property counts), stale @FieldResult or mappedBy paths left over from when an attribute was an embeddable, collections missing @ElementCollection/@OneToMany so their element type resolves as unknown, and the Hibernate 6.2 Byte[]/Character[] wrapper-array semantics change.
- Duplicate or inconsistent mapping of the same table or class.Two mappings claim the same table with different logical column names, so logical-name lookup fails; or XML components for the same class were written by different teams enumerating different property lists.
What usually fixes it
- Boot the SessionFactory or EntityManagerFactory in a CI smoke test, per target dialect where possible. Nearly every error in this family surfaces at bootstrap, so a build-time boot test converts a failed deployment into a failed build.
- Match id-generation strategy and advanced features to what the database actually supports: use IDENTITY, TABLE, or UUID generators where sequences are unavailable, restrict identity columns to integer types on CockroachDB, keep getGeneratedKeys enabled on Spanner, and let Hibernate resolve the dialect from the JDBC URL instead of hardcoding one.
- Keep annotations internally coherent: pick one optimistic-locking strategy per entity (@OptimisticLock(ALL/DIRTY) always with @DynamicUpdate and without @Version), give each distinct property combination of an embeddable its own Java class and use @AttributeOverrides for column-only differences, declare explicit @DiscriminatorColumn/@DiscriminatorValue with literals parseable by the declared type, and point @Proxy only at interfaces.
- Prefer JPA annotations over hand-edited hbm.xml for new mappings, validate existing XML against the Hibernate XSD in CI, and give dynamic-map (entity-name) properties explicit type attributes since reflection cannot supply them.
- Repair references rather than working around them: make sure association targets are registered entities in the persistence unit, use logical (as-written) column names in referencedColumnName, and update mappedBy/referencedPropertyName/@FieldResult paths in the same commit that renames or restructures attributes.
- Before a Hibernate upgrade (notably 6.2), read the migration guide and set explicit transition flags such as hibernate.type.wrapper_array_handling, then re-run the boot smoke test so semantic changes fail loudly at build time.
Documented occurrences
- Encountered multiple component mappings for the same java class {embeddableClassName} with different property mappings. Every property mapping combination should have its own java class(hibernate/hibernate-orm)
- Native temporal exclusion column option is not supported by this dialect(hibernate/hibernate-orm)
- Expecting Component for id mapping with no id-attribute(hibernate/hibernate-orm)
- many-to-one attribute [%s] specified delete-orphan but is not specified as unique; remove delete-orphan cascading or specify unique="true"(hibernate/hibernate-orm)
- Could not format discriminator value to SQL string(hibernate/hibernate-orm)
- illegal identity column type(hibernate/hibernate-orm)
- Unable to determine foreign key target Type for many-to-one or one-to-one mapping: referenced-entity-name=[${associatedEntityName}], referenced-entity-attribute-name=[${lhsPropertyName}](hibernate/hibernate-orm)
- ${getClass().getName()} does not support identity key generation(hibernate/hibernate-orm)
- Entity '{name}' has 'OptimisticLockType.{optimisticLockStyle}' but declares a '@Version' field(hibernate/hibernate-orm)
- Could not format discriminator value to SQL string(hibernate/hibernate-orm)
- Entity '${name}' has 'OptimisticLockType.${optimisticLockStyle}' but is not annotated '@DynamicUpdate'(hibernate/hibernate-orm)
- Named native query [%s] did not specify query string(hibernate/hibernate-orm)
- Discriminator column mapping given for non-discriminated entity [" + entityName + "] as part of resultset mapping [" + registrationName + "](hibernate/hibernate-orm)
- Named native query [%s] specified both a resultset-ref and an inline mapping of results(hibernate/hibernate-orm)
- dialect does not support sequences(hibernate/hibernate-orm)
- Non-terminal property path did not reference FetchableContainer: " + navigablePath(hibernate/hibernate-orm)
- proxy must be either an interface, or the class itself: {}(hibernate/hibernate-orm)
- No column with logical name '{}' in table '{}'(hibernate/hibernate-orm)
- unsaved-value NEGATIVE may only be used with short, int and long types(hibernate/hibernate-orm)
- Could not parse discriminator value '{discriminatorValue}' as discriminator type '{discriminatorType}'(hibernate/hibernate-orm)
…and 235 more across the corpus — use search.
Honest provenance: generated on 2026-08-22 from AI-assisted analysis of the linked records. See how records are made.