hibernate/hibernate-orm · error · AnnotationException

Collection '{}' has foreign key in secondary table

Error message

Collection '{}' has foreign key in secondary table

What it means

A @OneToMany collection's foreign-key join columns must live in a primary table, not in a secondary table of the owning entity. When the resolved join columns report isSecondary(), CollectionBinder throws this AnnotationException, because collection FK maintenance against a secondary table is not a supported mapping.

Source

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

			PropertyHolder propertyHolder,
			PropertyData inferredData,
			MetadataBuildingContext context,
			MemberDetails property,
			AnnotatedJoinColumns joinColumns,
			OneToMany oneToManyAnn,
			ManyToMany manyToManyAnn,
			ElementCollection elementCollectionAnn,
			CollectionBinder collectionBinder) {

		//TODO enhance exception with @ManyToAny and @CollectionOfElements
		if ( oneToManyAnn != null && manyToManyAnn != null ) {
			throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData )
					+ "' is annotated both '@OneToMany' and '@ManyToMany'" );
		}
		final String mappedBy;
		if ( oneToManyAnn != null ) {
			if ( joinColumns.isSecondary() ) {
				throw new AnnotationException( "Collection '" + getPath( propertyHolder, inferredData )
						+ "' has foreign key in secondary table" );
			}
			collectionBinder.setFkJoinColumns( joinColumns );
			mappedBy = nullIfEmpty( oneToManyAnn.mappedBy() );
			collectionBinder.setTargetEntity( oneToManyAnn.targetEntity() );
			collectionBinder.setCascadeStrategy(
					aggregateCascadeTypes( oneToManyAnn.cascade(), property,
							oneToManyAnn.orphanRemoval(), context ) );
			collectionBinder.setOrphanRemoval( oneToManyAnn.orphanRemoval() );
			collectionBinder.setOneToMany( true );
		}
		else if ( elementCollectionAnn != null ) {
			if ( joinColumns.isSecondary() ) {
				throw new AnnotationException( "Collection '" + getPath( propertyHolder, inferredData )
						+ "' has foreign key in secondary table" );
			}
			collectionBinder.setFkJoinColumns( joinColumns );
			mappedBy = null;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Point the collection's @JoinColumn at a column in the owning entity's primary table
  2. Or drop the secondary-table mapping for that column and keep the FK in the primary table
  3. Consider mapping the collection from a separate entity whose own table owns the FK

Example fix

// before
@Entity
@SecondaryTable(name = "order_details",
    pkJoinColumns = @PrimaryKeyJoinColumn(name = "order_id"))
public class Order {
    @OneToMany
    @JoinColumn(name = "detail_order_id")   // resolves into order_details -> error
    List<OrderLine> lines;
}

// after
public class Order {
    @OneToMany(mappedBy = "order")   // FK lives in the child table (OrderLine.order)
    List<OrderLine> lines;
}
Defensive patterns

Strategy: validation

Validate before calling

// Smoke-test: build the SessionFactory once in CI; secondary-table FK errors fail the build
public class MappingSmokeTest {
    @Test
    void allMappingsBoot() {
        StandardServiceRegistry registry = new StandardServiceRegistryBuilder().build();
        Metadata metadata = new MetadataSources( registry )
            .addAnnotatedClass( Order.class )
            .addAnnotatedClass( OrderLine.class )
            .buildMetadata();
        try ( SessionFactory sf = metadata.getSessionFactoryBuilder().build() ) {
            // AnnotationException surfaces here instead of at production boot
        }
    }
}

Prevention

When it happens

Trigger: The entity has @SecondaryTable mapping and the collection's @JoinColumn resolves to a column of that secondary table (joinColumns.isSecondary() true) while oneToManyAnn != null.

Common situations: An entity split across tables with @SecondaryTable where a child collection's FK column was placed in the secondary table; column-name collisions causing resolution into the secondary table; refactoring a single-table entity into primary + secondary without moving collection mappings.

Related errors


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