skip to content

How do you decide whether to model a concept — say, a customer's shipping Address — as an Entity or a Value Object, and why might the same real-world concept be modeled differently in two different bounded contexts of the same system?

level: seniorimportance: must knowfreq 70%

answer

  1. ask: distinguish identical instances? independent lifecycle? shared reference by id?
  2. same noun, different bounded context, different model
  3. Address: shipping VO vs. KYC-verification Entity
  4. promote VO to Entity when requirements add shared-reference/editable-in-place needs

basics

~30 s

Ask: does the business need to track this specific instance over time and tell it apart from an identical-looking one, or does it just describe a value that's interchangeable if the details match? An address used just to ship a package is usually a Value Object (only the street/city/zip matters). But if a 'Verified Address' needs its own approval history and audit trail, it becomes an Entity with its own identity.

solid answer

~60 s

The decision hinges on three questions: (1) Does the business need to distinguish two instances with identical attributes as different things? (2) Does this concept have its own lifecycle that matters independently — created, updated, tracked over time — separate from its owner? (3) Do other parts of the system need to reference 'this specific one' by identity, rather than just by value? If yes to any, it's an Entity; if the concept is fully described by its attributes and any 'change' is really just swapping in a different value, it's a Value Object. The same real-world noun can land differently in different bounded contexts because the questions above get different answers depending on what that context cares about: in an Order-fulfillment context, a shipping Address is just delivery data attached to an order (Value Object). In a Fraud-review or Address-Verification context, an address might need its own identity, a verification-status history, and be referenced by id from multiple customer records (Entity) — the business genuinely cares about 'this particular verified address record' over time.

go deeper

for a junior

Should be able to classify a couple of straightforward examples correctly (e.g., Money is a VO, Customer is an Entity) with a one-line reason.

for a middle

Should apply at least one of the three decision questions consistently to a new example and recognize obvious identity needs (e.g., something referenced by a foreign key from multiple places should probably be an Entity).

for a senior

Should articulate that the decision is context-dependent per bounded context, walk through a concrete example like Address that resolves differently in two contexts, and reason about the cost of getting the classification wrong in either direction.

for a principal

Should guide a team through re-modeling a concept that needs to be promoted from Value Object to Entity as requirements evolve, including migration concerns, without treating it as a prior design failure.

## There is no universal checklist There's no universal checklist that classifies every concept correctly on the first try — the decision is always made relative to what a specific bounded context needs the concept to do, and DDD explicitly expects the same real-world noun to be modeled differently in different contexts because each context has a different reason to care about it. That said, three concrete questions do most of the work. ## The three questions that do most of the work 1. **First**: does the business need to tell apart two instances that have identical attribute values? If a `Color` is RGB(255, 0, 0), nobody cares whether it's 'the same red' as another red elsewhere (Value Object). If a `Customer` has identical name and email to another customer, the business still needs to treat them as two separate people with separate order histories (Entity) — attribute equality is irrelevant to 'is this the same customer.' 2. **Second**: does the concept have an independent lifecycle worth tracking — created, mutated over time, with history or status transitions that matter on their own? A `LineItem's` price might be a Value Object today but tracking a `PriceChange` history with timestamps and reasons turns each change record into something with its own identity and lifecycle. 3. **Third**: does anything else in the system need to hold a durable reference to 'this exact one' — a foreign key, an id in an API response, a pointer that must keep working even after the referenced thing's attributes change? If code elsewhere says 'give me the address with `id=482`' and expects the same record back regardless of edits, that requires an Entity. ## Why the same address flips between contexts Address is the textbook example of context-dependence precisely because all three answers can flip. - **In an Order-fulfillment/shipping context**, an address exists purely to tell a courier where to deliver a package: if two different orders happen to ship to the same address, there's no business reason to say 'these are the same address record' vs. 'coincidentally identical values' — they're just equal values, freely copyable, embedded directly on each Order (Value Object, typically mapped as a JPA `@Embeddable` with no id column of its own). - **In an Address-Verification or KYC compliance context**, the business might explicitly need: a persistent record of 'this address was verified on this date by process X', a status that transitions (PENDING -> VERIFIED -> FLAGGED), and multiple customer accounts referencing that one verified record by id so re-verifying it once updates the status everywhere referenced. That's unmistakably an Entity — it has identity, lifecycle, and shared reference semantics that the shipping context never needed. ## Getting it wrong in either direction The trade-off in getting this wrong runs in both directions. | The mis-modelling | What it costs you | |---|---| | **Over-modeling a Value Object as an Entity** (unnecessary identity, a database id, mutation-in-place) | adds bookkeeping cost for no benefit: an id-generation strategy, `equals()`/`hashCode()` discipline around the transient-id problem, and mutation-tracking machinery for a concept that never needed to be told apart from an identical one — classic overengineering showing up as unnecessary tables, unnecessary foreign keys, and slower code for zero domain benefit. | | **Under-modeling an Entity as a Value Object** (no identity, embedded, copy-by-value) | loses traceability: you can no longer answer 'which one', can't build a history/audit trail, and any place that needed a stable reference breaks — two logically-different verified-address records with the same current attribute values would incorrectly merge, hiding real history like a status flip-flop that compliance needed to see. | ## The silent requirements shift teams miss A concrete real-world case that regularly bites teams: an e-commerce platform starts with Address as an embedded Value Object on Customer (fine for years). A later feature needs 'default shipping address' selectable from a list of saved addresses per customer, with the ability to edit one saved address and have it reflected wherever it's currently selected as default. That's a silent requirements shift toward identity — 'this saved address record, referenced from multiple places, editable in place' — and teams that don't notice keep the Value Object model, implement 'editing' as replace-the-whole-embedded-value, and then discover that editing an address used as the default on one order doesn't update the same conceptual address as saved on the customer profile, because they were never actually the same identity-bearing thing — they were independent value copies that happened to start out equal. The fix is promoting Address to an Entity with its own id once the requirement to reference-and-edit-in-place appears, which is normal, expected DDD evolution, not a sign of an earlier mistake, since the original decision was correct for the requirements at the time.

  • If a concept starts as a Value Object and later needs to become an Entity, is that a sign the original design was wrong?
    No — it's normal domain evolution. The original modeling was correct for the requirements at the time (no need to distinguish or reference instances); a new requirement (shared editable reference, history tracking) genuinely changed what the business needs from that concept, and DDD expects models to be refactored as understanding deepens, not frozen forever.
  • Can a Value Object contain a reference to an Entity, or vice versa, or does that break the pattern?
    A Value Object can reference an Entity's identity (e.g., a ShippingLabel Value Object holding a customerId) without becoming an Entity itself, since it's still fully described by its own fields including that id value. An Entity commonly contains multiple Value Objects as attributes. What would break the pattern is a Value Object holding a mutable reference to a live, independently-changing Entity object, since that reintroduces the aliasing problem immutability is meant to prevent.
  • Is there a quick heuristic for borderline cases where the three questions don't give a clear answer?
    Ask whether the business would ever say 'the same X' about two instances with different attribute values, or 'a different X' about two instances with identical attribute values — if either phrasing makes sense, it's an Entity; if only 'equal X' or 'a different value of X' makes sense, it's a Value Object. When genuinely unclear, default to Value Object since it's cheaper and can be promoted later, whereas demoting an Entity after other code has taken dependencies on its id is usually more disruptive.

A hotel room number vs. the room's decor: from the front desk's perspective a room has identity — room 204 stays room 204 across renovations, and guests are billed to 'room 204' specifically (Entity). From an interior designer comparing which rooms have the ocean-view decor package, the specific room number is irrelevant — two rooms with identical decor are just the same decor value repeated (Value Object) — same physical space, two different lenses.

saying these in an interview costs you the question

  • Says the Entity vs. Value Object choice is a fixed, context-independent property of a concept like 'Address'
  • Can't explain why the same noun might be modeled differently in two parts of the same system
  • Defaults everything to Entity 'to be safe', ignoring the bookkeeping cost
  • Doesn't mention identity/reference needs as a deciding factor, focuses only on 'does it have many fields'
  • Treats promoting a VO to an Entity later as evidence of an original design mistake rather than normal evolution

context