hibernate/hibernate-orm · error · AnnotationException

Association '{}' is 'mappedBy' another entity and may not sp

Error message

Association '{}' is 'mappedBy' another entity and may not specify the '@JoinColumn'

What it means

The mappedBy side of an association is the unowned side: it mirrors the join defined by the owning side and cannot declare its own join mapping. detectMappedByProblem throws this AnnotationException when a mappedBy collection property also carries a direct @JoinColumn or @JoinColumns annotation.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java:1191

			includeInOptimisticLockChecks = !isMappedBy;
		}
		collection.setOptimisticLocked( includeInOptimisticLockChecks );
	}

	private void bindCache() {
		//set cache
		if ( isNotBlank( cacheConcurrencyStrategy ) ) {
			collection.setCacheConcurrencyStrategy( cacheConcurrencyStrategy );
			collection.setCacheRegionName( cacheRegionName );
		}
		collection.setQueryCacheLayout( queryCacheLayout );
	}

	private void detectMappedByProblem(boolean isMappedBy) {
		if ( isMappedBy ) {
			if ( property.hasDirectAnnotationUsage( JoinColumn.class )
					|| property.hasDirectAnnotationUsage( JoinColumns.class ) ) {
				throw new AnnotationException( "Association '"
						+ qualify( propertyHolder.getPath(), propertyName )
						+ "' is 'mappedBy' another entity and may not specify the '@JoinColumn'" );
			}
			if ( propertyHolder.getJoinTable( property ) != null ) {
				throw new AnnotationException( "Association '"
						+ qualify( propertyHolder.getPath(), propertyName )
						+ "' is 'mappedBy' another entity and may not specify the '@JoinTable'" );
			}
			if ( oneToMany ) {
				if ( property.hasDirectAnnotationUsage( MapKeyColumn.class ) ) {
					BOOT_LOGGER.mappedByShouldNotSpecifyMapKeyColumn(
							qualify( propertyHolder.getPath(), propertyName )
					);
				}
				if ( property.hasDirectAnnotationUsage( OrderColumn.class ) ) {
					BOOT_LOGGER.mappedByShouldNotSpecifyOrderColumn(
							qualify( propertyHolder.getPath(), propertyName )
					);

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove @JoinColumn/@JoinColumns from the mappedBy side
  2. Define the join column once on the owning side (the side without mappedBy)
  3. If this side must own the join, remove mappedBy and give this side @JoinColumn(s) - then clean the other side to mappedBy

Example fix

// before
@Entity
class Comment {
    @ManyToOne
    @JoinColumn(name = "post_id")
    Post post;
}

@Entity
class Post {
    @OneToMany(mappedBy = "post")
    @JoinColumn(name = "post_id")   // error: mappedBy side may not declare join columns
    List<Comment> comments;
}

// after
@Entity
class Post {
    @OneToMany(mappedBy = "post")   // join defined solely by Comment.post
    List<Comment> comments;
}
Defensive patterns

Strategy: validation

Validate before calling

// Reject @JoinColumn on the mappedBy side before boot
static void checkMappedByJoinColumns(Class<?>... entities) {
    for ( Class<?> c : entities ) {
        for ( Field f : c.getDeclaredFields() ) {
            String mappedBy = null;
            OneToMany otm = f.getAnnotation( OneToMany.class );
            ManyToMany mtm = f.getAnnotation( ManyToMany.class );
            if ( otm != null ) mappedBy = otm.mappedBy();
            if ( mtm != null ) mappedBy = mtm.mappedBy();
            boolean join = f.isAnnotationPresent( JoinColumn.class )
                || f.isAnnotationPresent( JoinColumns.class );
            if ( mappedBy != null && !mappedBy.isBlank() && join ) {
                throw new IllegalStateException( "mappedBy side declares @JoinColumn: "
                    + c.getName() + "." + f.getName() );
            }
        }
    }
}

Prevention

When it happens

Trigger: isMappedBy is true for the property and property.hasDirectAnnotationUsage(JoinColumn.class) or JoinColumns.class returns true during detectMappedByProblem; the parallel check for @JoinTable produces a sibling error.

Common situations: Specifying a FK column name on both sides of a bidirectional relation 'for symmetry'; migrating a unidirectional relation to bidirectional without removing the join column from what becomes the inverse side; generator output that always emits @JoinColumn.

Related errors


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