hibernate/hibernate-orm · error · AnnotationException
Attribute '%s' of entity '%s' is mapped by association '%s'
Error message
Attribute '%s' of entity '%s' is mapped by association '%s' but is not annotated '@Id'
What it means
Thrown by the else-branch of checkMappedId: @MapsId points at an entity whose identifier is simple (not a Component), so the dependent attribute must be a simple @Id. If isSimpleId(property) fails — the attribute is @EmbeddedId, @Embedded, or lacks @Id entirely — bootstrap fails with this AnnotationException.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java:1540
final String expectedTypeName = compositeId.getComponentClassName();
final String actualTypeName = property.getType().getName();
if ( !hasCompatibleType( actualTypeName, expectedTypeName ) ) {
throw new AnnotationException(
"Identifier attribute '%s' of entity '%s' has type '%s' but is mapped by association '%s' to entity '%s' with composite identifier type '%s'"
.formatted(
propertyName,
propertyHolder.getPersistentClass().getEntityName(),
actualTypeName,
mapsIdProperty.getPropertyName(),
referencedEntityName,
expectedTypeName
)
);
}
}
else {
if ( !isSimpleId( property ) ) {
throw new AnnotationException(
"Attribute '%s' of entity '%s' is mapped by association '%s' but is not annotated '@Id'"
.formatted(
propertyName,
propertyHolder.getPersistentClass().getEntityName(),
mapsIdProperty.getPropertyName()
)
);
}
}
}
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Replace the child's @EmbeddedId with a simple @Id attribute and keep @MapsId on the association (shared primary key pattern).
- Or annotate the mapped attribute itself with @Id (JPA derived identity variant: @Id on the @ManyToOne).
- If the child genuinely needs a composite key, give the parent a composite @EmbeddedId so both sides match shapes.
Example fix
// before (parent has @Id Long id)
@EmbeddedId
private ChildId id; // wrong: parent key is simple
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("parentId")
private Parent parent;
// after
@Id
private Long id; // same type as parent's simple id
@ManyToOne(fetch = FetchType.LAZY)
@MapsId
private Parent parent; Defensive patterns
Strategy: validation
Validate before calling
// assert simple-id parents are paired with simple @Id attributes
if (hasSimpleId(Parent.class) && idAttribute(Child.class).isAnnotationPresent(EmbeddedId.class)) {
throw new IllegalStateException("Child of simple-id parent must use @Id, not @EmbeddedId");
} Try / catch
try {
metadata = sources.buildMetadata();
} catch (AnnotationException e) {
failBuild("MapsId shape mismatch: " + e.getMessage());
} Prevention
- When simplifying a parent key to @Id, update all @MapsId children in the same commit.
- Keep a checklist of id-shape pairs (simple->simple, composite->composite) in the mapping module docs.
When it happens
Trigger: Parent has @Id Long id; child declares @ManyToOne @MapsId Parent parent together with @EmbeddedId ChildId (wrong shape), or the referenced parent attribute has no @Id at all. Fires when the referenced entity binding exists and getIdentifier() is not a Component.
Common situations: Switching a parent from composite to simple key while the child keeps @EmbeddedId; applying a composite-key MapsId template to a simple-key parent; annotating the mapped attribute with @Embedded instead of @Id; removing @Id during refactoring.
Related errors
- Attribute '%s' of entity '%s' is mapped by association '%s'
- Identifier attribute '%s' of entity '%s' has type '%s' but i
- Identifier property '" + getPath( holder, data ) + "' cannot
- Ambiguous persistent property methods declared by '%s': '%s'
- Property '" + qualify( classDetails.getName(), attributeMemb
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/d50741b811c5da54.
Report an issue: GitHub.