What's an Entity, Anyway?¶
I've worked with Domain-Driven Design for fifteen years, and I'll admit something I usually keep to myself. There's one concept in DDD whose point I've never quite gotten. Not because I haven't read Evans, and not because I haven't built systems around it. I've done both. But every time I sit with the concept of the Entity and ask myself what it's actually for, I come away with the same shrug. Value Objects feel intuitive. Aggregates feel intuitive. The Entity feels like a placeholder that everyone agreed to keep teaching anyway.
A conversation a few days ago finally produced the click I'd been waiting for, and the answer surprised me. The confusion wasn't a personal blind spot. The concept itself has been quietly hollowed out by the very ideas that surround it, and most of us keep teaching it as if that hadn't happened. The Entity isn't broken. It's overshadowed. And the shadow only lifts once you start asking what would happen if the thing casting it weren't there.
The Concept That Wouldn't Click¶
Let me set the scene. When I introduce someone to DDD, the building blocks come in roughly this order, and they land with roughly the following weight. A Value Object is a thing defined by its values. Two of them with the same data are indistinguishable, like an Address or a Money amount. Most developers nod at this immediately, because it's the same concept as a struct, a record, or an enum in their favorite language. They've already been doing it for years.
An Aggregate is a consistency boundary: a cluster of related objects that get loaded together, saved together, and that protect their invariants together. Once you've seen one race condition you couldn't reason about, you start to feel the appeal. The Aggregate gives you a unit of work that has a clear inside and a clear outside, and you can talk about it without ambiguity.
Then comes the Entity, and that's where the lecture, the textbook, and, in my case, the inner monologue all get a little quiet. An Entity, the definitions go, is a thing with identity that persists over time. Two Entities with identical data are still two different Entities, because identity matters more than data. The example everyone reaches for is a bank transaction, or a person, or some object whose continuity through change is the point. It sounds reasonable in isolation. But the moment I try to use the concept in actual modeling, it dissolves into something else, and I can't find the place where it does its own work.
What an Entity Was Originally Supposed To Be¶
I want to be fair to the concept. In the original framing, the Entity was doing real work. Evans introduced it as the answer to a specific question: what do you call something whose identity matters more than its current data? An account whose balance changes, but is still the same account. A book whose location moves around a library, but is still the same book. A patient whose chart fills up over years, but is still the same patient.
That part makes sense. There's a clear distinction between what something is and which one it is. The Entity captures the which, and the Value Object captures the what. Two transactions for the same amount on the same day are still two distinct events in the world, even if they look identical on a screen. The Entity is the modeling concept that lets you say "these are two, not one." That's a real job.
It's also, I now think, the only job that was ever uniquely the Entity's. And once you start introducing the rest of the DDD vocabulary, that job stops being uniquely hers.
Then the Aggregate Showed Up¶
Here's what happens the moment you accept the Aggregate as a first-class concept. The Aggregate becomes the thing that's loaded, the thing that's persisted, the thing that's addressed from the outside by an ID. The Aggregate is where the invariants live, because it's the consistency boundary. The Aggregate is what gets versioned, what gets concurrency-checked, what gets snapshotted if you go that route. When somebody says "send a command to this account," they mean the Account Aggregate, identified by its Aggregate Root's ID.
What's left for the Entity? A thing with a local ID inside the Aggregate. That's not nothing. But it's a lot less than the bold introduction promised. We started with "the modeling concept for things whose identity matters more than data," and we ended with "an internal element of an Aggregate that happens to need an ID for addressing." The first one is a philosophical claim about how to think about the world. The second is an implementation detail of how to structure a class.
There's a related angle I've written about before in Your Aggregate is Not a Table: developers coming from a relational background tend to map Aggregates to tables and Entities to rows, and that reflex erodes whatever distinct meaning the Entity was supposed to carry. By the time you've mapped everything to a table, the Entity is just a row with an ID, and you've stopped thinking about whether it deserved its own concept in the first place.
Event Sourcing Makes the Picture Even Sharper¶
Then comes Event Sourcing, and the Entity recedes another step. In an event-sourced system, you don't load Entities. You replay an Aggregate's events, and whatever internal structure the Aggregate happens to have, including any Entities, comes along for the ride as part of reconstructing the state. There's no separate persistence story for Entities. They have no individual lifecycle in storage. They are, quite literally, an implementation detail of the Aggregate's projection of its own events.
I notice this in practice all the time. Teams that move to Event Sourcing stop talking about Entities almost immediately, and not because anyone told them to. The concept stops doing visible work. The conversations are about commands, events, projections, and Aggregates. Entities show up as variables inside the Aggregate's code, not as objects in the model anyone draws on a whiteboard. The concept doesn't disappear. It just becomes invisible, because nothing in the day-to-day work points to it as a separate thing.
This is the part where, for years, I would silently conclude that I just didn't get it, and move on. The concept was there in the textbooks, and presumably someone, somewhere, needed it. I didn't.
The Concession That Took Me a While¶
Before I go further, I want to make a concession that took me a while to make. The Entity isn't quite a Value Object. I tried for a long time to reduce it to one, and there's always a residue.
The residue is sibling differentiation. Consider an Order Aggregate with two LineItems. Same product, same quantity, same price. Are they one position with quantity two, or two separate positions? In most domains, the answer is "the customer added them separately, so they're separate," and the system needs to be able to tell them apart. To do that, each LineItem needs its own local ID. A pure Value Object can't do this, because two Value Objects with the same data are the same thing.
So the Entity does have a load-bearing job in classical Aggregate-DDD, and the job is real. It's just narrower than the definition implies. It's "a Value Object with a local ID so I can address one of several otherwise-identical siblings." That's a useful structural element. It is not, in my own assessment, a foundational modeling concept on the same shelf as the Aggregate or the Value Object. It's a footnote that earned a chapter.
Calling it an Entity rather than describing it functionally is, I think, mostly historical habit. The name was right when Evans coined it. By the time the rest of the toolkit was in place around it, the name had become a label without a referent that did meaningful work on its own.
A Conversation a Few Days Ago¶
A few days ago, in a conversation with Bastian Waidelich about Dynamic Consistency Boundaries, we stumbled together onto a question that neither of us had quite articulated before. He'd been thinking about something specific to ESDM, the modeling language we built for Event-Sourced Domain Modeling: it doesn't have Entities. Aggregates, yes. Value Objects, yes. Events, commands, read models, all there. But no Entities.
When he pointed that out, I caught myself nodding without surprise. Of course there are no Entities in ESDM. In the Aggregate-based modeling that ESDM was originally built for, there's nothing left for an Entity to do at the model level. The Aggregate had already absorbed the work. We hadn't left Entities out as a statement. We'd left them out because nothing in the modeling vocabulary pointed at them.
But the conversation didn't stop there. Bastian's next observation was the one I'd been ignoring for years and finally couldn't. In Dynamic Consistency Boundaries, there's something missing, and the gap is shaped exactly like an Entity. Without a fixed Aggregate boundary, you can't lean on the Aggregate to do the identity-carrying work. The Aggregate isn't there to hide behind, and the thing that needs to be modeled doesn't have a name in the current vocabulary.
DCB Brings the Entity Back¶
If you haven't seen Dynamic Consistency Boundaries before, the short version is this. Classical Aggregate-DDD says: pick a consistency boundary, draw a wall around it, and treat everything inside as one unit. DCB says: don't pick the wall up front. Let the wall be computed per command, based on what invariants that command actually needs to protect. The boundary becomes a property of the operation, not a static decoration on the model.
This sounds like a small shift, but it has a curious side effect. When the Aggregate stops being a fixed structural element, all the work the Aggregate used to do quietly needs to find a new home. Identity is part of that work. In Aggregate-DDD, the question "what carries identity in this model?" had a trivial answer: the Aggregate Root does. In DCB, that answer is gone, and the question is suddenly open again.
This is, I now realize, where the Entity gets its job back. Not as the degenerate sibling-of-the-Aggregate that aggregate-DDD reduced it to, but as a first-class concept: a thing with identity that exists independently of any fixed aggregate clamp. In a DCB world, "what is this thing's identity?" isn't a question that gets answered by pointing at the surrounding Aggregate. There's no surrounding Aggregate. The Entity has to stand on its own, and now the name matches the role.
This is the click I'd been missing for fifteen years. The Entity concept wasn't wrong. It was being suffocated by a modeling style that gave the Aggregate too much of its job. The Aggregate hadn't replaced the Entity. It had absorbed the Entity into itself so thoroughly that nobody noticed the seam.
What This Means for How We Model¶
If you do classical Aggregate-DDD, I'd say this. Stop sweating the Entity-vs-Value-Object distinction at the modeling level. Most things you'd call Entities are Value Objects with local IDs, and treating them that way will not cost you anything you weren't already losing by calling them Entities. Reserve the word "Entity" for places where you genuinely need to talk about a thing's identity independently of the Aggregate it lives in, which, in this style of modeling, is hardly ever.
If you're starting to work in a DCB style, the conversation is different. The Entity comes back as a primary modeling concept, because there's no Aggregate to absorb it. You'll need a name for the identity-bearing thing, and "Entity" is the right name. It always was. It just hasn't had a job since the Aggregate showed up and took everything.
For ESDM, this is an open design question I find genuinely interesting. Today, ESDM doesn't have Entities, and that's been a clean fit for the Aggregate-based modeling it was built for. The DCB world might require us to revisit that decision, and not as a feature request but as a conceptual one. The vocabulary has to fit the style, and the style is starting to broaden.
Looking in the Wrong Place¶
Fifteen years of not-quite-getting the Entity came from looking for its job in a world where the Aggregate had already done it. The concept wasn't wrong. It was just in the wrong place. That's a more interesting answer than "I missed something the textbooks were trying to tell me," and I prefer it, because it means the concept and I weren't talking past each other after all. We were both waiting for the surrounding ideas to make space for the conversation.
DCB makes space. Whether or not you adopt DCB as your modeling style, the existence of the conversation is, I think, the most interesting thing happening in DDD right now. It puts the building blocks back on the table and asks which of them are load-bearing and which were quietly load-bearing for something else. The Entity, it turns out, was load-bearing for a job that the Aggregate took over the moment they were introduced together. Take the Aggregate out of the equation, and the Entity stands up again.
If you'd like to see what modeling looks like when the vocabulary is treated this carefully, head over to esdm.io and walk through a small example. ESDM is the language we built for thinking about this kind of question in a way that survives contact with the code, and the open design questions in this post are exactly the kind of conversation it's meant to host.
And if you'd like to talk to me about where the Entity actually fits in your team's modeling, or about anything else in the world of Event Sourcing, CQRS, and Domain-Driven Design, write to me at hello@thenativeweb.io. These are the conversations that, fifteen years in, I still find the most interesting.