hibernate/hibernate-orm · error · AnnotationException

Identifier attribute '%s' of entity '%s' has type '%s' but i

Error message

Identifier attribute '%s' of entity '%s' has type '%s' but is mapped by association '%s' to entity '%s' with composite identifier type '%s'

What it means

Thrown when @MapsId references an entity with a composite @EmbeddedId and the dependent attribute is @EmbeddedId, but its Java type does not match the referenced entity's composite id class. checkMappedId compares property.getType().getName() with compositeId.getComponentClassName() via hasCompatibleType and rejects mismatches, printing expected vs actual type names.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java:1525

			InFlightMetadataCollector collector) {
		final var referencedEntityName = mapsIdProperty.getClassOrElementName();
		final var referencedEntityBinding = collector.getEntityBinding( referencedEntityName );
		if ( referencedEntityBinding != null ) {
			if ( referencedEntityBinding.getIdentifier() instanceof Component compositeId ) {
				if ( !isEmbeddedId( property ) ) {
					throw new AnnotationException(
							"Attribute '%s' of entity '%s' is mapped by association '%s' but is not annotated '@EmbeddedId'"
									.formatted(
											propertyName,
											propertyHolder.getPersistentClass().getEntityName(),
											mapsIdProperty.getPropertyName()
									)
					);
				}
				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,

View on GitHub (pinned to fad1729dce)

Solutions

  1. Reuse the parent's embeddable id class as the child's @EmbeddedId type (or a compatible identical type per hasCompatibleType).
  2. If the child truly needs extra key columns, put them in an embeddable that embeds the parent id type as a nested field and keep the mapped attribute's type aligned.
  3. Alternatively abandon @MapsId and map the FK columns explicitly with @JoinColumn plus a separate id.

Example fix

// before
@Embeddable
public class ChildId implements Serializable {
    private Long parentId; // duplicate of ParentId - type mismatch
    private String extra;
}

@EmbeddedId
private ChildId id;

// after: reuse the parent's id type
@Embeddable
public class ChildId implements Serializable {
    @Embedded
    private ParentId parentId; // same type as parent's @EmbeddedId
    private String extra;
}

@EmbeddedId
private ChildId id;

@ManyToOne(fetch = FetchType.LAZY)
@MapsId("parentId")
private Parent parent;
Defensive patterns

Strategy: validation

Validate before calling

// assert child EmbeddedId type equals parent EmbeddedId type before bootstrap
Class<?> parentIdType = parentIdEmbeddable(Parent.class); // e.g. ParentId
Class<?> childIdType = childEmbeddedIdType(Child.class);
if (!parentIdType.equals(childIdType)) {
    throw new IllegalStateException("Child id type " + childIdType.getName()
        + " must match parent's " + parentIdType.getName());
}

Try / catch

try {
    metadata = sources.buildMetadata();
} catch (AnnotationException e) {
    failBuild("MapsId type mismatch (expected vs actual in message): " + e.getMessage());
}

Prevention

When it happens

Trigger: Parent uses @EmbeddedId ParentId; child declares @EmbeddedId with a hand-written ChildId class that duplicates the fields instead of reusing the parent's id class (or uses an unrelated embeddable). Fires only when the parent binding is registered and its identifier is a Component.

Common situations: Developers writing a 'local' embeddable for the child's composite key instead of reusing the parent's id class; refactoring the parent's id class to a new name while the child keeps the old one; code-generated id classes diverging between modules.

Related errors


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