Entity Base Class

If you follow DDD principles, you eventually end up creating a base class for all the domain entities. It’s a good idea as it allows you to gather common logic in one place. When you decide to do that, you inevitably face the question what exactly should be included in that base entity and how it should be presented.

Interface as a base entity

I often see developers using interfaces as a base entity. Their code might look like this:

public interface IEntity


    int Id { get; }


While this approach guarantees that all domain entities have some minimum functionality (Id property in this example), in most cases having an interface as a base entity is a bad idea.

First of all, interfaces don’t allow you to gather any logic in them, you need to implement this logic yourself which leads to a massive code duplication. Even in the example above you need to create the Id property in every single entity, which itself is a heavy violation of the DRY principle.

Secondly, using an interface doesn’t show the appropriate relationship between the domain entities. When a class implements an interface it makes a promise about some functionality, and that’s it. Two classes implementing the same interface don’t give any promises about their relationship, they can belong to entirely unconnected hierarchies. In other words, IEntity interface introduces a “can do” relation (according to Bertrand Meyer’s classification), whereas domain entities should be connected to the base entity by “is a” relation. Every domain class not only has the Id property, but itself is an entity. It is important to remove possible misunderstandings, using an interface instead of the base class can lead to one.

How you shouldn’t implement base classes

Okay, but what logic do we need in the base domain class?
Obviously, it should have an Id field, which is mapped to a table’s primary key. All tables in the database must have ids with the same type so we could factor the Id property out to the base class. Here is how you should not do it:

public class Entity<T>


    public T Id { get; protected set; }


Motivation for such code it pretty clear: you have a base class that can be reused across multiple projects. For instance, if there is a web application with GUID Id columns in the database and a desktop app with integer Ids, it might seem a good idea to have the same class for both of them. In fact, this approach introduces accidental complexity because of premature generalization. There is no need in using a single base entity class for more than one project or bounded context. Each domain has its unique path, so let it grow independently. Just copy and paste the base entity class to a new project and specify the exact type that will be used for the Id property.

There’s a case I want to mention, though. Although you should create tables with primary keys of the same type only, you may have a legacy application, created by different developers, where they have database tables with primary keys of different types. Or there might be composite primary keys. In these cases, there is no way to inherit your domain classes from the same base class. The best solution here might be refactoring your database, although you should consider pros and cons of such decision. For a new project, you should always create database tables with a single Id column of the same type.

Entity base class: the code

So, what should the base domain class look like? Here is the code I use in production, let’s step through it.

By default the Id property is of long type, which excludes the possibility of sequence exhausting. Also, all members are made virtual, because I use NHibernate where virtual members are required to create runtime proxies. Setter is made protected and not private because of NHibernate as well.

The most interesting part is equality members, which is generally the rest part of the class. To go further, we should step back and recall what it means to be equal.

There are three types of equality in enterprise software:

  • Reference equality means that two references refer to the same object in memory.
  • Identifier equality means that two different objects in memory refer to the same row in the database.
  • Logical equality means that two different objects and two different rows in the database are actually equal. It might happen when an object doesn’t have its own identity (such objects called value objects), and thus we can treat two different objects with identical fields as logically equal.

The Entity class covers the first two situations: when two objects either equal by reference or by identifier. Logical equality pertains to Value Objects I will cover later. Note, that GetRealType method is called in order to get the type of the objects. GetRealType() was added to the base class because NHibernate returns runtime proxy class type if you just call GetType() on an object, so we must call NHibernateUtil.GetClass() to get the underlying object type.

The second “if” statement in Equals method checks reference equality and the last one checks identifier equality. IsTransient method refers to the notion of objects’ states. They can be either saved in DB (this state is called persistent) or not saved (this state is called transient). It doesn’t matter why an object can be not saved: either because it was deleted or because insert wasn’t done in DB yet, this state is called transient regardless of the reason.

We must check the objects’ state because transient objects have Id property set to zero by default. We cannot check identifier equality if one of the objects doesn’t have the identifier yet. But if you assign the id by yourself, using non-native id generation strategy in NHibernate, then you can skip this.

GetHashCode method must be overridden together with the Equals method as well. They always come together because of the internal .NET logic. This logic can be illustrated in the code below. When you call Contains() method it loops through the objects in the list and calls GetHashCode() on each object. If the codes coincide it also calls Equal(). And only if the both checks, GetHashCode and Equal, are passed two objects considered as equal.

Entity obj = GetObjectSomehow();

List<Entity> objects = GetObjectsSomehow();


It is a good idea to declare == and != operators as well, because by default == operator checks reference equality only.


I use this code in most of my projects, sometimes adding some functionality if it appears in all project’s domain classes. Such functionality might be version property (byte[] or int) or any other useful stuff. But don’t be carried away by this, add functionality to the base domain class if it belongs to all domain classes only. Otherwise, you may end up building God Object instead of a thin base entity.

Update 4/1/2019

The Entity base class no longer contains the GetRealType method and doesn’t rely on NHibernate anymore. Thanks to Anders Baumann for suggesting the workaround.


  • GSerjo

    Nice article. Why you didn’t implement IEquatable on Enity?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      IEquatable doesn’t provide any additional value here. The main use case for this interface is structs: it allows you to avoid unnecessary boxing/unboxing operations. Reference types can just use basic Equals(object) method.

  • Marcos Antonio

    Good article!!

    About your base class implementation, where the Entity class should reside? In my case, this class is inside the namespace MyApp.Domain (this is a class library) and according to DDD, the domain can’t reference any kind of technology or framework.

    My main doubt is because of this code:

    public virtual Type GetRealType()


    return NHibernateUtil.GetClass(this);


    There is a reference to NHibernate. Is that corret?

    Where is the correct place to put that base class?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Excellent question!

      Indeed, the domain classes should be as decoupled from any ORM (or other technology) as possible, this principle is called Persistence Ignorance. Nevertheless, it is not always possible to completely remove ORM’s artifacts from your code. For example, if you use NHibernate, you need to mark all non-private class members as virtual. Another example: in Entity Framework, you can’t use private fields or properties in order to map them to database columns.

      There should be a balance here. Domain entities should be as persistent ignorant as possible, but at the same time, you aren’t be able to ignore your ORM completely, you need to conform to it at least at some point.

      GetRealType() is one of such trade-offs. I occasionally use it to find out the real type of the proxies that NHibernate generates, and it seems that the base Entity class is a good place to keep this logic. Entity class itself resides in MyApp.Domain assembly with the other domain classes.

      One point here: I advocate you follow YAGNI principle so add the GetRealType method to your base class only if you really use it. If not, don’t add it, you will always be able to add it later.

      Thank you for your comment!

      • Anders Baumann

        Hi Vladimir.
        I think I found a way to get the real type without having a dependency to NHibernate (which I also want to avoid in my domain project). See this article: http://sessionfactory.blogspot.com/2010/08/hacking-lazy-loaded-inheritance.html.
        So Equals can be written like this:

        public override bool Equals(object obj)
        var compareTo = obj as Entity;
        if (compareTo is null) return false;
        if (ReferenceEquals(this, compareTo)) return true;
        if (Actual.GetType() != compareTo.Actual.GetType()) return false;
        return !IsTransient() && !compareTo.IsTransient() && Id == compareTo.Id;

        public virtual object Actual => this;

        It seems to work. What do you think?


        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          That seems like a really nice workaround! Will try it out and update the article, thanks!

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          Updated the post.

  • Milad EP

    Thank you for your sharing,

    But I think it is impossible that use a non-generic class for all of the entities, because sometimes we need to use big-int,guid and the other types as primary keys and it will limit us to use this class as base class.
    The bast way I think to use a Generic with the Implementation of your class with inheriting an interface like IEntity for allowing user to re-use the base class in the other places.
    According to GetRealType and using Nhibernate.GetRealClass, I think it is a bad practice and we have to use an abstract method in this way and let the user to redefine a base class that inherited from your base class, in this way we’ve saved our base class from ORMs and we’ll able to re-use the base class for the other ORMs like EF in the current solution.

    What is your opinion?!

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Milad, thanks for your comment.

      I personally think that programmers should try to be consistent with entities’ Ids within a single bounded context. I would consider having different types of primary keys a bad practice in this case. Note that you don’t have to be consistent across all bounded contexts in your domain model, it’s fine to have a BC with entities’ identifiers of the int type and another BC with GUIDs. In this case, I would create 2 different base entity classes, one for each BC.

      Regarding GetRealType – this is indeed an ORM abstraction leaking into the domain model. Trying to create as pure domain model as possible, we have to be pragmatic, though, and I would say that this “dirty” piece of code is justified in this particular case. However, the alternative you propose is nice and would work if you want to completely unbind the Entity class from the ORM concerns.

      To summarize:
      – I don’t recommend introducing an IEntity interface or an Entity base class.
      – Your alternative for the GetRealType method looks good.

      Hope that helps.

      • Milad EP

        Hi Vladimir,

        Could you please let me know your opinion about don’t using Generic classes as base class?
        What is the problem if we are using a BC as generic and what may be happens there?!

        If it s possible for you that provide me some references or short response about this topic, I’ll be thankful.


        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          Hi Milad,

          The main advantage I see in having a unified identifier type across the whole bounded context is simplicity. It’s easier to use a single common denominator for that purpose and not bother with multiple types of Ids. Of course, you can have a generic entity class to handle all possible identifier types, but to me, that’s an unnecessary over-complication.

          There’s no hard rule here, though, and I don’t see problems with the generic Entity base class other than what I just mentioned.

  • Subhash

    As C# does not support multiple inheritance, What if I have to inherit the class with other base class like Employee is a Person so Employee must be inherit from Person rather than Entity?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      As long as Person itself inherits from Entity, there’s nothing stopping you from doing so, you don’t have to inherit from Entity directly.

      • Subhash

        Thanks for quick response.
        Actually I have more complex scenario like,
        1) Entity Base class
        public abstract class Entity

        public abstract class AuditableEntity : Entity, IAuditableEntity
        public int CreatedBy {get; private set;}
        public DateTime CreatedOn {get; private set;}

        public abstract class AuditableTemporalEntity : AuditableEntity, ITemporalEntity
        public DateTime ValidFrom {get; private set;}
        public DateTime ValidTill {get; private set;}

        public abstract class HistoryEntity: Entity, IHistoryEntity
        public int HistoryId {get; private set;}
        public string Action {get; private set;}

        public class Employee : AuditableTemporalEntity

        public class EmployeeHistory: HistoryEntity

        In each base classes, I have implemented common behaviours like Activate, DeActivate methods in AuditableEntity class etc.

        So, in this case, I have already inherit Person by AuditableTemporalEntity like,

        public abstract class Person: AuditableTemporalEntity

        but now I cannot inherit Person to EmployeeHistory class.

        I have tried by solving this approach by implementing interfaces directly to classes but as you mentioned, it’s violate DRY principle by duplicate properties and behaviours.

        Also tried by generic extension methods but then I have to set public “setters” in interfaces so I can set properties value in extension methods as generic extension methods using constraint by interfaces.

  • Xavier L.

    Hi Vladimir,

    I understand the reason behind your advice of overloading == and != operators.

    But what about double dispatch ? Let’s say I have two entities x and y with the same Id, but for some reason, one of them is stored as an object.

    In this case, x.Equals(y) will return true, but x == y will return false, as the types needed for the overloaded == operator won’t be met, and the test will fallback to the default == operator which compares references.

    Can’t this overloading be confusing in this case ? I understand this is an edge case, but anyway, this seems to introduces a non negligible behavior difference. Any thoughts about this ?
    Thanks 🙂

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Well, you can’t do anything with it anyway. This problem exists with all .NET types, including BCL (for example, String). The general guideline here is that if you are going to use polymorphic comparison, you need to call Equals(), not operator==. That’s btw what such classes as ArrayList do when you call Contains().

      • Xavier L.

        Ah, of course it does apply everywhere… We just have to be cautious on the == operator usage. Thanks !

  • Stefan Adriaenssen

    Hello, I noticed your Equals method takes into account the IsTransient property, but your GetHashCode method does not. What happens if you have 2 new objects (different objects, but both transient) and you want to store them for example in a HashTable? Isn’t this going to give some kind of conflict?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Stefan, yes it would introduce an issue if you use them as a key in a Dictionary. I wouldn’t say it’s problem, though, because using mutable objects as a hash table key is an anti-pattern anyway. The purpose of GetHashCode here is to comply with such methods as Contains() in BCL, which it fulfills well.

      • Matt

        Actually, this GetHashCode implementation is not EF Core friendly. EF Core sets negative unique IDs on transient entities when they are attached to the context. In my case, the entities belonged to a HashSet collection on a principal and as a result of the hash code changing with the new IDs, the entities were duplicated in the collection. For now I have commented out the GetHashCode method since EF Core is “used” to working with entities that do not define one.

  • Ali Rezaei

    public virtual Type GetRealType()
    return NHibernateUtil.GetClass(this);
    This is surely very hacky. There should never be a reason to introduce ORM specific framework into your base entity. There are much better workarounds and it should be reflected in this article. As this could unfortunately misguide a junior developer that this is good practice. A good design shouldn’t cater to any framework.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      This has been fixed thanks to Anders Baumann’s comment below.

  • http://www.alireza-rahmani.ir/ alireza Rahmani khalili

    if you inject Entity object then why you check if it is null?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      If you mean operator ==, then you still need to check it for null as you can write something like
      bool b = myEntity == null;

      You would still need to introduce your own comparison even with UUIDs.

  • Benjamin Vertonghen

    It might work for NHibernate but it won’t work for Entity Framework Core.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Any specific case where it might not work?

      • Matt

        Please see my comment below.

  • nemke

    Seems like the blog text does not follow the code or vice versa?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      It should. Although I modified the code since then, so it might be the case. Any specific inconsistencies?

      • nemke

        The Entity class covers the first two situations: when two objects either equal by reference or by identifier. Logical equality pertains to Value Objects I will cover later. Note, that GetRealType method is called in order to get the type of the objects. GetRealType() was added to the base class because NHibernate returns runtime proxy class type if you just call GetType() on an object, so we must call NHibernateUtil.GetClass() to get the underlying object type.

        There is no GetRealType() method in your code. As I can see in comments, you used alternative from comment

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          Ah, indeed. I’ll update the article, thanks.

  • http://www.duanewingett.info Dibley

    We have recently started using SonarQube for code analysis and it raises `”operator==” should not be overloaded on reference types`


    The use of == to compare to objects is expected to do a reference comparison. That is, it is expected to return true if and only if they are the same object instance. Overloading the operator to do anything else will inevitably lead to the introduction of bugs by callers. On the other hand, overloading it to do exactly that is pointless; that’s what == does by default.


    What are your thoughts on this please, as now I don’t know whether to keep the operator overloads in or not.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      I disagree with this guideline. How to compare two instances of a type depends on the domain meaning (semantics) of that type, not whether it’s a class or a struct, that’s just an implementation detail.

      • http://www.duanewingett.info Dibley

        Hi Vladimar,

        Thank you for taking the time to clarify. I shall bear that in mind and take the SonarQube warning with a pinch if salt, in this situation.

  • 3amprogrammer

    Hi Vladimir, great post as always! I have one question. What are your thoughts on using natural key as entity’s primary key? To me it’s unpractical. User might make a mistake while entering tax id (in Poland it’s called NIP and it’s unique to the company). The same goes with email address or even ID number. What are your insights on this? I know a few people that like this cause it’s nice in theory. You don’t have some ugly and technical uuid.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Natural keys are a no-go. There are problems with them: they change (you may make a mistake and want to correct it), they are not guaranteed to be unique. Always use surrogate keys.

      If you need additional ammunition in discussions with colleagues: Fowler wrote about this issue in his P of EAA book and he shares the same view.

      • 3amprogrammer

        I though so. Thanks for the reply, I really appreciate you devote your time for answering our questions!