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 '@EmbeddedId'

What it means

Thrown by PropertyBinder.checkMappedId when a @ManyToOne/@OneToOne association uses @MapsId but the referenced entity's identifier is a composite @EmbeddedId while the dependent attribute is not itself annotated @EmbeddedId. JPA derived-identity rules require that when the parent key is an EmbeddedId, the dependent's id must be an EmbeddedId embeddable containing the mapped attribute. Bootstrap fails immediately after Hibernate resolves the referenced entity binding.

Source

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

				return mapsIdProperty;
			}
		}
		else {
			return collector.getPropertyAnnotatedWithMapsId( classDetails, isId ? "" : propertyName );
		}
	}

	private static void checkMappedId(
			PropertyHolder propertyHolder,
			MemberDetails property,
			String propertyName, PropertyData mapsIdProperty,
			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(),

View on GitHub (pinned to fad1729dce)

Solutions

  1. Change the child's identifier to an embeddable containing the parent key field and annotate it @EmbeddedId, keeping @MapsId on the association pointing at that field.
  2. If the composite parent key is unwanted, simplify the parent back to a simple @Id so MapsId pairs @Id to @Id.
  3. If you do not need a derived identity, drop @MapsId and map a plain FK column with @JoinColumn.

Example fix

// before (parent has @EmbeddedId ParentId)
@Id
@Column(name = "parent_id")
private Long parentId; // wrong shape: parent key is composite
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("parentId")
private Parent parent;

// after
@Embeddable
public class ChildId implements Serializable {
    private ParentId parentId; // same embeddable type as parent's id
}

@EmbeddedId
private ChildId id;

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

Strategy: validation

Validate before calling

// before adding classes, assert MapsId children of EmbeddedId parents use EmbeddedId
for (Class<?> parent : parentsWithEmbeddedId()) {
    for (Class<?> child : entitiesMappingIdOf(parent)) {
        Field f = idAttribute(child);
        if (!f.isAnnotationPresent(EmbeddedId.class)) {
            throw new IllegalStateException(child.getSimpleName()
                + " maps id of " + parent.getSimpleName() + " but lacks @EmbeddedId");
        }
    }
}

Try / catch

try {
    metadata = sources.buildMetadata();
} catch (AnnotationException e) {
    // message names the attribute, entity and association - surface it to the mapper
    failBuild("Derived identity misconfigured: " + e.getMessage());
}

Prevention

When it happens

Trigger: Parent entity has @EmbeddedId ParentId id; child declares @MapsId("parentId") on the association but uses a simple @Id Long parentId, or no id at all. Fires when the referenced entity binding is already registered and getIdentifier() returns a Component (composite).

Common situations: Converting a simple-key parent to a composite key and forgetting the child's id shape; copying a MapsId pattern from a simple-id example; parent/child tables sharing a composite natural key; teams deriving FK primary keys per JPA 2.4.1 without matching the embeddable shape.

Related errors


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