hibernate/hibernate-orm · error · AnnotationException

Association '%s' is 'mappedBy' a property '%s' of entity '%s

Error message

Association '%s' is 'mappedBy' a property '%s' of entity '%s' with multiple columns

What it means

The property this association is 'mappedBy' maps to MULTIPLE columns (a composite value: multi-column type, embeddable, or composite FK). Deriving the inverse side's single default join/order column requires exactly one column, so Hibernate rejects it. (The message prints the holder path twice due to an upstream formatting quirk — the third %s should be the entity name.)

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java:630

								getPropertyHolder().getPath(),
								getMappedByPropertyName(),
								getMappedByEntityName()
						)
				);
			}
			if ( !(value.getSelectables().get( 0 ) instanceof Column column) ) {
				throw new AnnotationException(
						String.format(
								Locale.ENGLISH,
								"Association '%s' is 'mappedBy' a property '%s' of entity '%s' which maps to a formula",
								getPropertyHolder().getPath(),
								getMappedByPropertyName(),
								getPropertyHolder().getPath()
						)
				);
			}
			if ( value.getSelectables().size() > 1 ) {
				throw new AnnotationException(
						String.format(
								Locale.ENGLISH,
								"Association '%s' is 'mappedBy' a property '%s' of entity '%s' with multiple columns",
								getPropertyHolder().getPath(),
								getMappedByPropertyName(),
								getPropertyHolder().getPath()
						)
				);
			}
			return column.getNameIdentifier( getBuildingContext() );
		}

		@Override
		public MetadataBuildingContext getBuildingContext() {
			return AnnotatedJoinColumns.this.getBuildingContext();
		}
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Map the collection WITHOUT relying on the derived single column: use an explicit @JoinTable, or leave the association unidirectional from the owning side.
  2. Simplify the owning side to a single-column @JoinColumn if the schema permits.
  3. For composite FKs with @MapsId-style derived ids, mirror each column explicitly instead of using mappedBy.

Example fix

// before
@Entity
class Invoice {
    // composite FK: order_id + line_no
    @ManyToOne
    @JoinColumns({@JoinColumn(name = "order_id"), @JoinColumn(name = "line_no")})
    OrderLine line;
}

@Entity
class OrderLine {
    @OneToMany(mappedBy = "line") // -> error: multiple columns
    List<Invoice> invoices;
}

// after
@Entity
class OrderLine {
    @OneToMany
    @JoinTable(name = "line_invoices",
        joinColumns = {@JoinColumn(name = "order_id"), @JoinColumn(name = "line_no")},
        inverseJoinColumns = @JoinColumn(name = "invoice_id"))
    List<Invoice> invoices;
}
Defensive patterns

Strategy: validation

Validate before calling

// Guard: mappedBy owner must map exactly one column
String mappedBy = "line";
Field owner = Invoice.class.getDeclaredField(mappedBy);
JoinColumns jcs = owner.getAnnotation(JoinColumns.class);
int n = jcs == null
    ? (owner.getAnnotation(JoinColumn.class) != null ? 1 : 0)
    : jcs.value().length;
if (n > 1) throw new IllegalStateException(
    "mappedBy '" + mappedBy + "' maps " + n + " columns; use a @JoinTable instead");

Try / catch

try {
    factory = cfg.buildSessionFactory();
} catch (AnnotationException e) {
    // 'with multiple columns' -> map the collection with an explicit
    // @JoinTable listing every composite column
    throw newConfigurationException("Composite mappedBy owner", e);
}

Prevention

When it happens

Trigger: '@OneToMany(mappedBy = "x")' where x is a @ManyToOne with a composite key (@JoinColumns with 2+ columns, or a composite @EmbeddedId target); the owning side maps an embeddable with several @Columns; mappedBy points at a property whose value.getSelectables().size() > 1.

Common situations: Composite primary keys in legacy schemas; trying to add an inverse collection to an association whose FK spans two columns; aggregating columns into one property via a custom composite user type.

Related errors


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