hibernate/hibernate-orm · error · AnnotationException
Attribute '" + memberDetails.getName() + "' is declared by '
Error message
Attribute '" + memberDetails.getName() + "' is declared by '" + memberDetails.getDeclaringType().getName() + "' and may not be redeclared as an '@Id' or '@EmbeddedId' by '" + property.getDeclaringType().getName() + "'
What it means
The mirror case of the generation-strategy error: an attribute that a superclass declares as a plain (non-id) property is redeclared in a subclass as @Id or @EmbeddedId. Hibernate's id-property bookkeeping cannot promote an inherited attribute to identifier status, so AnnotationException is thrown while reconciling id properties.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java:786
|| !property.getMetaAnnotated( IdGeneratorType.class, context ).isEmpty() ) {
//TODO: it would be nice to allow a root @Entity to override an
// @Id field declared by a @MappedSuperclass and change the
// generator, but for now we don't seem to be able to detect
// that case here
throw new AnnotationException(
"Attribute '" + memberDetails.getName()
+ "' is declared as an '@Id' or '@EmbeddedId' property by '"
+ memberDetails.getDeclaringType().getName()
+ "' and so '" + property.getDeclaringType().getName()
+ "' may not respecify the generation strategy" );
}
}
else {
//TODO: it would be nice to allow a root @Entity to override a
// field declared by a @MappedSuperclass, redeclaring it
// as an @Id field, but for now we don't seem to be able
// to detect that case here
throw new AnnotationException(
"Attribute '" + memberDetails.getName()
+ "' is declared by '" + memberDetails.getDeclaringType().getName()
+ "' and may not be redeclared as an '@Id' or '@EmbeddedId' by '"
+ property.getDeclaringType().getName() + "'" );
}
}
}
static boolean hasIdAnnotation(MemberDetails element) {
return isSimpleId( element ) || isEmbeddedId( element );
}
/**
* Process annotation of a particular property or field.
*/
public static void processElementAnnotations(
PropertyHolder propertyHolder,
Nullability nullability,View on GitHub (pinned to fad1729dce)
Solutions
- Remove @Id/@EmbeddedId from the subclass redeclaration.
- If the subtype truly needs its own identity, remove the conflicting attribute from the superclass and declare the @Id field on the subclass (or split the hierarchy).
- Restructure so the identifier is declared at one level only: either the shared root (@MappedSuperclass/@Entity) or the concrete entity — never promoted from below.
Example fix
// before
@MappedSuperclass
public abstract class Base {
protected String code;
}
@Entity
public class Product extends Base {
@Override
@Id // promoting an inherited plain attribute => rejected
public String getCode() { return code; }
}
// after: declare the id at one level
@MappedSuperclass
public abstract class Base { /* no 'code' here */ }
@Entity
public class Product extends Base {
@Id
private String code;
} Defensive patterns
Strategy: validation
Validate before calling
// A subclass may not promote an inherited plain attribute to @Id
for (Class<?> entity : annotatedClasses) {
Class<?> sup = entity.getSuperclass();
while (sup != null && (sup.isAnnotationPresent(MappedSuperclass.class) || sup.isAnnotationPresent(Entity.class))) {
for (Field own : entity.getDeclaredFields()) {
if (!own.isAnnotationPresent(Id.class)) continue;
try {
Field supF = sup.getDeclaredField(own.getName());
if (!supF.isAnnotationPresent(Id.class)) {
throw new IllegalStateException(entity.getName() + " redeclares inherited attribute " + own.getName() + " as @Id");
}
} catch (NoSuchFieldException ignored) { }
}
sup = sup.getSuperclass();
}
} Try / catch
try {
SessionFactory sf = cfg.buildSessionFactory();
} catch (AnnotationException e) {
throw new IllegalStateException("Id redeclaration conflict: " + e.getMessage(), e);
} Prevention
- Declare identifiers at a single hierarchy level
- When introducing @Id on a subclass field, remove the inherited attribute from the superclass
When it happens
Trigger: @MappedSuperclass declares private String code; the subclass adds @Id on its overriding code field/getter; hierarchies where a subtype was supposed to own its primary key but the field already exists higher up.
Common situations: Refactoring single-table hierarchies so a subtype becomes independently identifiable; merging unrelated entities under a common base class; generated code that adds @Id to every concrete class's fields.
Related errors
- Attribute '${attribute}' is declared as an '@Id' or '@Embedd
- Property '${property}' is annotated '@OptimisticLock(exclude
- Mapped superclass '{}' may not specify an '@Inheritance' map
- Property '${property}' belongs to an entity subclass and may
- Property '${property}' is annotated '@OptimisticLock(exclude
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/e1a182ed22256675.
Report an issue: GitHub.