diff --git a/src/db.c b/src/db.c
index 0e8661f02..ac9b5d3d8 100644
--- a/src/db.c
+++ b/src/db.c
@@ -584,8 +584,8 @@ serverDb *initTempDb(void) {
     serverDb *tempDb = zcalloc(sizeof(serverDb) * server.dbnum);
     for (int i = 0; i < server.dbnum; i++) {
         tempDb[i].id = i;
-        tempDb[i].keys = kvstoreCreate(&dbDictType, slot_count_bits, flags);
-        tempDb[i].expires = kvstoreCreate(&dbExpiresDictType, slot_count_bits, flags);
+        tempDb[i].keys = kvstoreCreate(&kvstoreKeysDictType, slot_count_bits, flags);
+        tempDb[i].expires = kvstoreCreate(&kvstoreExpiresDictType, slot_count_bits, flags);
     }
 
     return tempDb;
diff --git a/src/dict.h b/src/dict.h
index 40fa284d2..4d46cf8b6 100644
--- a/src/dict.h
+++ b/src/dict.h
@@ -70,10 +70,6 @@ typedef struct dictType {
      * computing the length of the key + header when buf is NULL. */
     size_t (*embedKey)(unsigned char *buf, size_t buf_len, const void *key, unsigned char *header_size);
 
-
-    /* Data */
-    void *userdata;
-
     /* Flags */
     /* The 'no_value' flag, if set, indicates that values are not used, i.e. the
      * dict is a set. When this flag is set, it's not possible to access the
diff --git a/src/kvstore.c b/src/kvstore.c
index b7fa7359a..ca48f8df5 100644
--- a/src/kvstore.c
+++ b/src/kvstore.c
@@ -52,7 +52,7 @@ static dict *kvstoreIteratorNextDict(kvstoreIterator *kvs_it);
 
 struct _kvstore {
     int flags;
-    dictType dtype;
+    dictType *dtype;
     dict **dicts;
     long long num_dicts;
     long long num_dicts_bits;
@@ -86,6 +86,7 @@ struct _kvstoreDictIterator {
 /* Dict metadata for database, used for record the position in rehashing list. */
 typedef struct {
     listNode *rehashing_node; /* list node in rehashing list */
+    kvstore *kvs;
 } kvstoreDictMetadata;
 
 /**********************************/
@@ -166,7 +167,9 @@ static dict *createDictIfNeeded(kvstore *kvs, int didx) {
     dict *d = kvstoreGetDict(kvs, didx);
     if (d) return d;
 
-    kvs->dicts[didx] = dictCreate(&kvs->dtype);
+    kvs->dicts[didx] = dictCreate(kvs->dtype);
+    kvstoreDictMetadata *metadata = (kvstoreDictMetadata *)dictMetadata(kvs->dicts[didx]);
+    metadata->kvs = kvs;
     kvs->allocated_dicts++;
     return kvs->dicts[didx];
 }
@@ -197,9 +200,9 @@ static void freeDictIfNeeded(kvstore *kvs, int didx) {
  * If there are multiple dicts, updates the bucket count for the given dictionary
  * in a DB, bucket count incremented with the new ht size during the rehashing phase.
  * If there's one dict, bucket count can be retrieved directly from single dict bucket. */
-static void kvstoreDictRehashingStarted(dict *d) {
-    kvstore *kvs = d->type->userdata;
+void kvstoreDictRehashingStarted(dict *d) {
     kvstoreDictMetadata *metadata = (kvstoreDictMetadata *)dictMetadata(d);
+    kvstore *kvs = metadata->kvs;
     listAddNodeTail(kvs->rehashing, d);
     metadata->rehashing_node = listLast(kvs->rehashing);
 
@@ -214,9 +217,9 @@ static void kvstoreDictRehashingStarted(dict *d) {
  *
  * Updates the bucket count for the given dictionary in a DB. It removes
  * the old ht size of the dictionary from the total sum of buckets for a DB.  */
-static void kvstoreDictRehashingCompleted(dict *d) {
-    kvstore *kvs = d->type->userdata;
+void kvstoreDictRehashingCompleted(dict *d) {
     kvstoreDictMetadata *metadata = (kvstoreDictMetadata *)dictMetadata(d);
+    kvstore *kvs = metadata->kvs;
     if (metadata->rehashing_node) {
         listDelNode(kvs->rehashing, metadata->rehashing_node);
         metadata->rehashing_node = NULL;
@@ -230,7 +233,7 @@ static void kvstoreDictRehashingCompleted(dict *d) {
 }
 
 /* Returns the size of the DB dict metadata in bytes. */
-static size_t kvstoreDictMetadataSize(dict *d) {
+size_t kvstoreDictMetadataSize(dict *d) {
     UNUSED(d);
     return sizeof(kvstoreDictMetadata);
 }
@@ -253,20 +256,9 @@ kvstore *kvstoreCreate(dictType *type, int num_dicts_bits, int flags) {
     assert(num_dicts_bits <= 16);
 
     kvstore *kvs = zcalloc(sizeof(*kvs));
-    memcpy(&kvs->dtype, type, sizeof(kvs->dtype));
+    kvs->dtype = type;
     kvs->flags = flags;
 
-    /* kvstore must be the one to set these callbacks, so we make sure the
-     * caller didn't do it */
-    assert(!type->userdata);
-    assert(!type->dictMetadataBytes);
-    assert(!type->rehashingStarted);
-    assert(!type->rehashingCompleted);
-    kvs->dtype.userdata = kvs;
-    kvs->dtype.dictMetadataBytes = kvstoreDictMetadataSize;
-    kvs->dtype.rehashingStarted = kvstoreDictRehashingStarted;
-    kvs->dtype.rehashingCompleted = kvstoreDictRehashingCompleted;
-
     kvs->num_dicts_bits = num_dicts_bits;
     kvs->num_dicts = 1 << kvs->num_dicts_bits;
     kvs->dicts = zcalloc(sizeof(dict *) * kvs->num_dicts);
@@ -760,7 +752,7 @@ void kvstoreDictLUTDefrag(kvstore *kvs, kvstoreDictLUTDefragFunction *defragfn)
 }
 
 uint64_t kvstoreGetHash(kvstore *kvs, const void *key) {
-    return kvs->dtype.hashFunction(key);
+    return kvs->dtype->hashFunction(key);
 }
 
 void *kvstoreDictFetchValue(kvstore *kvs, int didx, const void *key) {
diff --git a/src/kvstore.h b/src/kvstore.h
index 202f6a9c2..81a0d9a96 100644
--- a/src/kvstore.h
+++ b/src/kvstore.h
@@ -37,6 +37,10 @@ int kvstoreNumAllocatedDicts(kvstore *kvs);
 int kvstoreNumDicts(kvstore *kvs);
 uint64_t kvstoreGetHash(kvstore *kvs, const void *key);
 
+void kvstoreDictRehashingStarted(dict *d);
+void kvstoreDictRehashingCompleted(dict *d);
+size_t kvstoreDictMetadataSize(dict *d);
+
 /* kvstore iterator specific functions */
 kvstoreIterator *kvstoreIteratorInit(kvstore *kvs);
 void kvstoreIteratorRelease(kvstoreIterator *kvs_it);
diff --git a/src/lazyfree.c b/src/lazyfree.c
index 38ccd913b..6176b4344 100644
--- a/src/lazyfree.c
+++ b/src/lazyfree.c
@@ -192,8 +192,8 @@ void emptyDbAsync(serverDb *db) {
         flags |= KVSTORE_FREE_EMPTY_DICTS;
     }
     kvstore *oldkeys = db->keys, *oldexpires = db->expires;
-    db->keys = kvstoreCreate(&dbDictType, slot_count_bits, flags);
-    db->expires = kvstoreCreate(&dbExpiresDictType, slot_count_bits, flags);
+    db->keys = kvstoreCreate(&kvstoreKeysDictType, slot_count_bits, flags);
+    db->expires = kvstoreCreate(&kvstoreExpiresDictType, slot_count_bits, flags);
     atomic_fetch_add_explicit(&lazyfree_objects, kvstoreSize(oldkeys), memory_order_relaxed);
     bioCreateLazyFreeJob(lazyfreeFreeDatabase, 2, oldkeys, oldexpires);
 }
diff --git a/src/server.c b/src/server.c
index 3aaddd38d..0a148ae33 100644
--- a/src/server.c
+++ b/src/server.c
@@ -474,26 +474,32 @@ dictType zsetDictType = {
     NULL,              /* allow to expand */
 };
 
-/* Db->dict, keys are sds strings, vals are Objects. */
-dictType dbDictType = {
+/* Kvstore->keys, keys are sds strings, vals are Objects. */
+dictType kvstoreKeysDictType = {
     dictSdsHash,          /* hash function */
     NULL,                 /* key dup */
     dictSdsKeyCompare,    /* key compare */
     NULL,                 /* key is embedded in the dictEntry and freed internally */
     dictObjectDestructor, /* val destructor */
     dictResizeAllowed,    /* allow to resize */
+    kvstoreDictRehashingStarted,
+    kvstoreDictRehashingCompleted,
+    kvstoreDictMetadataSize,
     .embedKey = dictSdsEmbedKey,
     .embedded_entry = 1,
 };
 
-/* Db->expires */
-dictType dbExpiresDictType = {
+/* Kvstore->expires */
+dictType kvstoreExpiresDictType = {
     dictSdsHash,       /* hash function */
     NULL,              /* key dup */
     dictSdsKeyCompare, /* key compare */
     NULL,              /* key destructor */
     NULL,              /* val destructor */
     dictResizeAllowed, /* allow to resize */
+    kvstoreDictRehashingStarted,
+    kvstoreDictRehashingCompleted,
+    kvstoreDictMetadataSize,
 };
 
 /* Command table. sds string -> command struct pointer. */
@@ -540,7 +546,7 @@ dictType keylistDictType = {
 };
 
 /* KeyDict hash table type has unencoded Objects as keys and
- * dicts as values. It's used for PUBSUB command to track clients subscribing the channels. */
+ * dicts as values. It's used for PUBSUB command to track clients subscribing the patterns. */
 dictType objToDictDictType = {
     dictObjHash,          /* hash function */
     NULL,                 /* key dup */
@@ -550,6 +556,20 @@ dictType objToDictDictType = {
     NULL                  /* allow to expand */
 };
 
+/* Same as objToDictDictType, added some kvstore callbacks, it's used
+ * for PUBSUB command to track clients subscribing the channels. */
+dictType kvstoreChannelDictType = {
+    dictObjHash,          /* hash function */
+    NULL,                 /* key dup */
+    dictObjKeyCompare,    /* key compare */
+    dictObjectDestructor, /* key destructor */
+    dictDictDestructor,   /* val destructor */
+    NULL,                 /* allow to expand */
+    kvstoreDictRehashingStarted,
+    kvstoreDictRehashingCompleted,
+    kvstoreDictMetadataSize,
+};
+
 /* Modules system dictionary type. Keys are module name,
  * values are pointer to ValkeyModule struct. */
 dictType modulesDictType = {
@@ -2626,8 +2646,8 @@ void initServer(void) {
         flags |= KVSTORE_FREE_EMPTY_DICTS;
     }
     for (j = 0; j < server.dbnum; j++) {
-        server.db[j].keys = kvstoreCreate(&dbDictType, slot_count_bits, flags);
-        server.db[j].expires = kvstoreCreate(&dbExpiresDictType, slot_count_bits, flags);
+        server.db[j].keys = kvstoreCreate(&kvstoreKeysDictType, slot_count_bits, flags);
+        server.db[j].expires = kvstoreCreate(&kvstoreExpiresDictType, slot_count_bits, flags);
         server.db[j].expires_cursor = 0;
         server.db[j].blocking_keys = dictCreate(&keylistDictType);
         server.db[j].blocking_keys_unblock_on_nokey = dictCreate(&objectKeyPointerValueDictType);
@@ -2642,10 +2662,10 @@ void initServer(void) {
     /* Note that server.pubsub_channels was chosen to be a kvstore (with only one dict, which
      * seems odd) just to make the code cleaner by making it be the same type as server.pubsubshard_channels
      * (which has to be kvstore), see pubsubtype.serverPubSubChannels */
-    server.pubsub_channels = kvstoreCreate(&objToDictDictType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND);
+    server.pubsub_channels = kvstoreCreate(&kvstoreChannelDictType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND);
     server.pubsub_patterns = dictCreate(&objToDictDictType);
-    server.pubsubshard_channels =
-        kvstoreCreate(&objToDictDictType, slot_count_bits, KVSTORE_ALLOCATE_DICTS_ON_DEMAND | KVSTORE_FREE_EMPTY_DICTS);
+    server.pubsubshard_channels = kvstoreCreate(&kvstoreChannelDictType, slot_count_bits,
+                                                KVSTORE_ALLOCATE_DICTS_ON_DEMAND | KVSTORE_FREE_EMPTY_DICTS);
     server.pubsub_clients = 0;
     server.watching_clients = 0;
     server.cronloops = 0;
diff --git a/src/server.h b/src/server.h
index e34fc680e..0b4c4c6c2 100644
--- a/src/server.h
+++ b/src/server.h
@@ -2637,7 +2637,8 @@ extern dictType objectKeyHeapPointerValueDictType;
 extern dictType setDictType;
 extern dictType BenchmarkDictType;
 extern dictType zsetDictType;
-extern dictType dbDictType;
+extern dictType kvstoreKeysDictType;
+extern dictType kvstoreExpiresDictType;
 extern double R_Zero, R_PosInf, R_NegInf, R_Nan;
 extern dictType hashDictType;
 extern dictType stringSetDictType;
@@ -2645,7 +2646,7 @@ extern dictType externalStringType;
 extern dictType sdsHashDictType;
 extern dictType clientDictType;
 extern dictType objToDictDictType;
-extern dictType dbExpiresDictType;
+extern dictType kvstoreChannelDictType;
 extern dictType modulesDictType;
 extern dictType sdsReplyDictType;
 extern dictType keylistDictType;