Skip to main content

Patternintermediate

Entity

Overview

An entity is an object defined by its identity, not by its attributes. Two orders with exactly the same data are different orders if they have different identifiers.

The distinction between an entity and a value object is the first tactical modelling decision, and it comes from the domain — not from technical convenience.

Problem

Not everything you persist is an entity. Treating everything as an entity produces three problems.

Identity where there is none. An address with its own identifier, referenced by other objects, raises the question "is this the same address?" — which has no useful answer in the domain.

Improper mutability. Entities change over time; value objects do not. Making mutable something that should be replaced opens a class of sharing defects.

Wrong comparison. Two entities compare by identity; two value objects, by attributes. Getting that wrong produces subtly incorrect behaviour in collections and caches.

The test that settles it: if two objects with the same attributes can be different to the business, it is an entity.

Core Concepts

The identity belongs to the domain

The entity has identity because the domain distinguishes it over time. A customer remains the same customer after changing address, name and phone number.

That means the identity has to be stable: it never changes while the entity exists.

Choosing the identifier is architectural

One of the system's highest-cost-of-reversal decisions, and frequently taken by whoever writes the first migration. See what is architecture.

StrategyAdvantageCost
Database sequenceCompact, ordered, efficient indexOnly exists after persisting; exposes volume; hard in distributed systems
UUID generated in the applicationExists before persisting; no coordinationLarger; worse index locality
Time-ordered UUIDNo coordination and good localityLess widely supported
Natural domain keyMeaning of its ownChanges when reality changes

The fourth row deserves attention: natural identifiers — a tax number, a contract number, a product code — look ideal and fail when the business changes the rule. A product code that "never changes" changes at the first catalogue merger.

The practical recommendation: use an artificial identifier as the identity, and treat the natural one as a unique attribute. That separates identity from the business rule that may change.

Generate the identity early

An identifier generated by the database only exists after persistence. That prevents building an object graph in memory before saving, and complicates tests.

Generating in the application — a UUID or equivalent — solves it: the identity exists before the write, the graph is assembled in memory and the test needs no database.

The entity has behaviour

An entity with only fields and accessors is the anemic model. The rules that protect its invariant belong to it. See encapsulation.

When to Use

  • The domain distinguishes the object over time, even as attributes change.
  • There is a history or lifecycle associated with it.
  • Other objects need to reference it stably.
  • There are rules that depend on "this specific object".

When Not to Use

When the object is defined by its values. Money, address, period, coordinate. See value object.

When the identity has no meaning in the domain. If nobody asks "which one?", it probably is not an entity.

When the domain does not distinguish two identical occurrences. It is the same axis as the condition above, inverted: immutability decides nothing here — two payments of the same amount, on the same day, by the same person are different payments, and neither of them changes after being created. An immutable entity exists; what does not exist is an entity with no identity.

In supporting or generic subdomains. The ceremony of tactical modelling does not pay off outside the core.

Alternatives

  • Value object — when the attributes define it.
  • A transparent record — for data with no invariant and no identity.
  • A plain identifier — when it is enough to reference without carrying the object.

Trade-offs

EntityValue object
Stable identity over timeDefined by attributes
MutableImmutable
Comparison by identityBy value
Lifecycle and historyReplaced, not altered
Persisted with an identifierCan be embedded
Referenced by identifierCopied where it is used

Failure Modes

Unstable identity. The identifier changes, and every reference breaks.

A natural identifier that changes. A corrected tax number, a renumbered product code.

Anemic entity. No behaviour; the invariant gets scattered.

Comparison by attributes. Two instances of the same entity treated as different in a collection.

Identity exposed in a public contract. A sequential identifier in an API reveals business volume and allows enumeration.

Common Mistakes

Treating everything as an entity. The most common mistake and the one that most complicates the model.

Using a natural identifier as the identity.

Depending on the database to generate the identity.

Leaving the entity anemic.

Exposing the internal identifier in external contracts. Consider a separate public identifier.

Real-World Example

An equipment rental system modelled Equipment as an entity — with an identifier — and Contract too.

The delivery Address was also an entity, with its own table and identifier.

The problem appeared on correcting an address: altering the record changed the address on every historical contract that referenced it. A two-year-old contract came to show the customer's current address, not the original delivery one.

That is an auditing defect in a domain with contractual implications.

Remodelling made Address a value object, embedded in each contract. Correcting the customer's address stopped affecting past contracts, because each one carries the address that applied at the time.

What revealed the mistake was the test question: are two addresses with the same data the same address? For the domain, yes — and that means it is not an entity.

The counterexample in the same system: Equipment remains an entity, because two drills of the same model are different pieces of equipment, with their own maintenance and rental histories.

Practical Exercise

List your domain's persisted classes. For each, apply the test: are two objects with the same attributes the same object to the business?

The ones answering "yes" are candidates for becoming value objects.

Then check, for the entities, which identity strategy each uses and what would happen if the identifier had to change.

Interview Questions

  • How do you distinguish an entity from a value object?
  • What are the risks of using a natural identifier?
  • Why generate the identity in the application rather than in the database?

Further Exploration

  • Evans, Eric. Domain-Driven Design. Addison-Wesley, 2003.
  • Vernon, Vaughn. Implementing Domain-Driven Design. Addison-Wesley, 2013 — the chapter on identity.
Finished reading this document?Your progress is saved in this browser only.