HardExperience level: 8-15 years3 min read

equals/hashCode Under Inheritance — Interview Questions

Reviewed by Gurusankar M.

Asked inAmazonOracleMicrosoftDeloitte
#equals#hashcode#inheritance#symmetry#hibernate
Report issue

Short Answer

Adding a value field in a subclass makes it nearly impossible to keep equals() symmetric and transitive with its superclass — the classic Point/ColorPoint problem. You get two imperfect options: use getClass() (breaks Liskov — a subclass is never equal to its parent) or instanceof (can break symmetry/transitivity). The clean fixes: prefer composition over inheritance for value types, or define equality on a stable business key. With Hibernate, proxies and generated ids make identity-based equals dangerous.

On this page

Concept Made Simple

Coffee Chat Question

“How does the equals()/hashCode() contract break under inheritance, and with ORM proxies?”

Remember It Faster

Mind Map Answer

The trap: once a subclass adds a significant field, no equals() can satisfy reflexive + symmetric + transitive with the parent at the same time. It's a genuine design conflict, not a coding mistake.

getClass()
Symmetric, but breaks Liskov (no subtype equality)
instanceof
Allows subtype equality, risks asymmetry
Best fix
Composition over inheritance for value types
Hibernate
Use a business key, not the generated id

Hibernate/JPA: entities are wrapped in proxies (so getClass() != real class → use instanceof), and the id is null until persisted (so id-based hashCode changes after save, corrupting HashSets). Equality on an immutable natural/business key avoids both.

Key takeaway: value equality and inheritance don't mix cleanly — favour composition, base equality on immutable business keys, and never key a HashSet on a field that changes after construction/persistence.

Learn by Doing

Hands-on Keyboard

java
@Entity
class User {
    @Id @GeneratedValue Long id;          // null until persisted!
    @Column(unique = true) String email;   // stable business key

    @Override public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User other)) return false;
        return email != null && email.equals(other.email);  // key, not id
    }
    @Override public int hashCode() {
        return Objects.hashCode(email);     // stable across persist
    }
}

Think Beyond the Expected

What If?

Why is basing a JPA entity's hashCode on its @GeneratedValue id dangerous?

Because the id is null before the entity is persisted and gets assigned on flush — so an entity's hashCode changes after you've already added it to a HashSet/HashMap. Once the hash changes, the collection can't find the element (it's in the wrong bucket), leading to duplicates, lost lookups, and leaks. Base equals/hashCode on an immutable business key (email, natural id) that's set at construction and never changes, so identity is stable across the entity's whole lifecycle.

Real World

Any project mixing JPA entities with HashSet/HashMap membership hits this: entities 'disappear' from sets after being saved, or bidirectional associations behave oddly, all because id-based hashCode changed on flush. Teams standardise on business-key equality (or documented reference equality) to keep collections correct.

Interviewer's Expectation

Keywords they're listening for:

  • subclass value field breaks symmetry
  • getClass breaks Liskov, instanceof risks asymmetry
  • composition over inheritance
  • business key over generated id
  • Hibernate proxy + null-id pitfalls

Common Mistakes

  • Basing entity hashCode on a generated id
  • Mixing inheritance with value equality
  • Using getClass() and being surprised proxies never match

Best Practices

  • Prefer composition for value types
  • Use immutable business keys for entity equality
  • Consider records for simple immutable value objects

Follow-up Questions

  1. getClass() vs instanceof in equals — trade-offs?
  2. Why do records sidestep some of these issues?
  3. How do Hibernate proxies affect getClass() comparisons?

Continue Learning with AI

Take this question deeper with your favourite AI assistant. Pick a depth, copy the prompt, or open it directly — AI is your learning companion, not a shortcut.

Plain-language foundations

I'm preparing for a software engineering interview and want to understand this from scratch, as a beginner.

Topic: Object Contract (Advanced Java)
Interview question: "How does the equals()/hashCode() contract break under inheritance, and with ORM proxies?"

Please:
1. Explain the core idea in simple, plain language, using an everyday analogy.
2. Define any technical terms you use.
3. Walk through one small, concrete example.
4. Finish with a single sentence I can easily remember.

Keep the tone friendly and assume I'm new to this topic.
Open inChatGPTGeminiClaude

Was this answer helpful?

Affiliate links

Equipment for a comfortable, productive setup.

As an Amazon Associate I earn from qualifying purchases.