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

  1. Replace the child's @EmbeddedId with a simple @Id attribute and keep @MapsId on the association (shared primary key pattern).
  2. Or annotate the mapped attribute itself with @Id (JPA derived identity variant: @Id on the @ManyToOne).
  3. 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 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


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