hibernate/hibernate-orm · error · UnsupportedMappingException

@SoftDelete cannot be applied to @OneToMany - {}.{}

Error message

@SoftDelete cannot be applied to @OneToMany - {}.{}

What it means

@SoftDelete marks an entity type as soft-deletable; it belongs on the entity class (the target of deletion), never on a @OneToMany collection property. CollectionBinder.checkAnnotations throws this UnsupportedMappingException when a one-to-many property directly carries @SoftDelete.

Source

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

				: new WrappedInferredData(inferredData, "element" );
	}

	private static void checkAnnotations(
			PropertyHolder propertyHolder,
			PropertyData inferredData,
			MemberDetails property,
			OneToMany oneToMany,
			ManyToMany manyToMany,
			ElementCollection elementCollection) {
		if ( ( oneToMany != null || manyToMany != null || elementCollection != null )
				&& isToManyAssociationWithinEmbeddableCollection( propertyHolder ) ) {
			throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData ) +
					"' belongs to an '@Embeddable' class that is contained in an '@ElementCollection' and may not be a "
					+ annotationName( oneToMany, manyToMany, elementCollection ));
		}

		if ( oneToMany != null && property.hasDirectAnnotationUsage( SoftDelete.class ) ) {
			throw new UnsupportedMappingException(
					"@SoftDelete cannot be applied to @OneToMany - " +
							property.getDeclaringType().getName() + "." + property.getName()
			);
		}

		if ( property.hasDirectAnnotationUsage( OrderColumn.class )
				&& manyToMany != null
				&& isNotBlank( manyToMany.mappedBy() ) ) {
			throw new AnnotationException("Collection '" + getPath( propertyHolder, inferredData ) +
					"' is the unowned side of a bidirectional '@ManyToMany' and may not have an '@OrderColumn'");
		}

		if ( manyToMany != null || elementCollection != null ) {
			if ( property.hasDirectAnnotationUsage( JoinColumn.class )
					|| property.hasDirectAnnotationUsage( JoinColumns.class ) ) {
				throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData )
						+ "' is a " + annotationName( oneToMany, manyToMany, elementCollection )
						+ " and is directly annotated '@JoinColumn'"

View on GitHub (pinned to fad1729dce)

Solutions

  1. Move @SoftDelete from the @OneToMany property to the target entity class
  2. If several entities participate, annotate each soft-deletable entity class with @SoftDelete
  3. Keep the @OneToMany side free of soft-delete annotations; filtering is derived from the target entity's soft-delete setup

Example fix

// before
@Entity
class Parent {
    @OneToMany(mappedBy = "parent")
    @SoftDelete                  // error: belongs on the child entity
    List<Child> children;
}

// after
@Entity
@SoftDelete
public class Child {
    @ManyToOne
    Parent parent;
}

@Entity
class Parent {
    @OneToMany(mappedBy = "parent")
    List<Child> children;
}
Defensive patterns

Strategy: validation

Validate before calling

// Reject @SoftDelete placed on @OneToMany properties before boot
static void checkSoftDeletePlacement(Class<?>... entities) {
    for ( Class<?> c : entities ) {
        for ( Field f : c.getDeclaredFields() ) {
            if ( f.isAnnotationPresent( SoftDelete.class )
                    && f.isAnnotationPresent( OneToMany.class ) ) {
                throw new IllegalStateException( "@SoftDelete on @OneToMany property: "
                    + c.getName() + "." + f.getName() );
            }
        }
    }
}

Prevention

When it happens

Trigger: A property with @OneToMany also has a direct @SoftDelete annotation (property.hasDirectAnnotationUsage(SoftDelete.class) is true during checkAnnotations).

Common situations: Adopting Hibernate's soft-delete feature and assuming the annotation goes where deletion is observed (the collection) rather than on the deleted entity; upgrading codebases that used custom soft-delete solutions with collection-level markers.

Related errors


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