Value Object vs Entity
Entities have identity (two Customer objects with the same data are still different customers if they have different IDs). Value Objects have no identity — they are defined entirely by their attributes (two Money objects with amount=100 and currency=USD are interchangeable).
Value Object vs Entity = dollar bills vs people. Two $10 bills are interchangeable — you don't care which specific bill you have (value object). But two people named 'John Smith' are NOT interchangeable — identity matters (entity).
Value Objects are immutable, equality is by value, they have no lifecycle of their own, and they are replaceable. Entities are mutable (over time), equality is by identity (ID), and they have a lifecycle. Design choice: if you can replace one instance with another of the same value and nothing in the system cares, it is a Value Object. Examples: Money, DateRange, EmailAddress, Color — Value Objects. Customer, Order, Product — Entities.
Value Objects enforce invariants at construction time — a Money object with negative amount throws in the constructor. This eliminates the scattered null checks and boundary validations typical of primitive types. This is the cure for 'primitive obsession' anti-pattern: instead of storing price as a double (no invariants, no currency), use Money (validated, self-describing, currency-aware). Value Objects can be used as map keys and in sets because their equals() and hashCode() are value-based. In persistence: JPA maps Value Objects with @Embeddable — they are stored in the same table as the owning entity with no surrogate key. DDD aggregates often use Value Objects for attributes that have complex validation: Address, DateRange, PhoneNumber.
The Entity vs Value Object distinction is central to clean domain modeling. I make Money a Value Object: final class, private final BigDecimal amount, private final Currency currency, all validation in the constructor, equals/hashCode by value, no setters. Two Money(100, USD) objects are identical — I can use either one. A Customer is an Entity: it has a customerId that persists across mutations. Two customers with the same name and address are still different entities. The practical impact: Value Objects are safe to pass by value, copy freely, and use as map keys. Entities must be compared by ID, and their lifecycle must be managed carefully.
Do not make everything an Entity out of habit. Primitive obsession — using int or String for domain concepts — is a design smell. An EmailAddress as a String has no format validation, no domain methods, and no self-documentation. Elevate it to a Value Object.