diff --git a/core/src/main/java/me/yushust/message/EntityResolver.java b/core/src/main/java/me/yushust/message/EntityResolver.java
new file mode 100644
index 0000000..cff3b37
--- /dev/null
+++ b/core/src/main/java/me/yushust/message/EntityResolver.java
@@ -0,0 +1,33 @@
+package me.yushust.message;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * A functional interface that resolves an entity using
+ * a {@code T} instance
+ * Example:
+ *
+ * class IdEntityResolver implements EntityResolver {
+ *
+ * private EntityStore store = ...;
+ *
+ * public Entity resolve(UUID id) {
+ * return store.find(id);
+ * }
+ * }
+ *
+ * @param The entity tpye
+ * @param The resolvable type
+ */
+@FunctionalInterface
+public interface EntityResolver {
+
+ /**
+ * Resolves an entity using a {@code T} instance.
+ * @param object The resolving object
+ * @return The resolved entity
+ */
+ @Nullable
+ E resolve(T object);
+
+}
diff --git a/core/src/main/java/me/yushust/message/generic/EntityResolverRegistry.java b/core/src/main/java/me/yushust/message/generic/EntityResolverRegistry.java
new file mode 100644
index 0000000..785e462
--- /dev/null
+++ b/core/src/main/java/me/yushust/message/generic/EntityResolverRegistry.java
@@ -0,0 +1,50 @@
+package me.yushust.message.generic;
+
+import me.yushust.message.EntityResolver;
+import me.yushust.message.util.Validate;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Represents a registry of entity resolvers
+ * @param The entity type
+ */
+public class EntityResolverRegistry {
+
+ private final Map, EntityResolver> resolvers
+ = new HashMap<>();
+
+ /**
+ * Finds an already registered {@link EntityResolver} and
+ * returns it wrapped with {@link Optional}. If the entity resolver
+ * isn't present, returns an empty {@linkplain Optional}
+ * @param resolvableType The resolvable type
+ * @return The entity resolver
+ */
+ public Optional> findResolver(Class resolvableType) {
+
+ Validate.notNull(resolvableType, "resolvableType");
+ EntityResolver resolver = resolvers.get(resolvableType);
+
+ // it's safe, the map is modified only by
+ // EntityResolverRegistry#addResolver that
+ // adds the resolver using a generic method
+ @SuppressWarnings("unchecked")
+ EntityResolver castedResolver = (EntityResolver) resolver;
+ return Optional.of(castedResolver);
+ }
+
+ /**
+ * Registers an entity resolver to the backing map
+ * @param resolvableType The resolvable type
+ * @param resolver The resolver
+ */
+ public void addResolver(Class resolvableType, EntityResolver resolver) {
+ Validate.notNull(resolvableType, "resolvableType");
+ Validate.notNull(resolver, "resolver");
+ resolvers.put(resolvableType, resolver);
+ }
+
+}