diff --git a/include/opendht/indexation/pht.h b/include/opendht/indexation/pht.h
index 05ca637f3e32de2b00739471b6eb67b6b973bfa0..d60afbe1f903d7045137ececf15a4e5fab7315a8 100644
--- a/include/opendht/indexation/pht.h
+++ b/include/opendht/indexation/pht.h
@@ -142,6 +142,9 @@ struct IndexEntry : public dht::Value::Serializable<IndexEntry> {
 };
 
 class Pht {
+    static constexpr const char* INVALID_KEY = "Key does not match the PHT key spec.";
+
+    /* Prefixes the user_type for all dht values put on the DHT */
     static constexpr const char* INDEX_PREFIX = "index.pht.";
 
 public:
@@ -150,7 +153,11 @@ public:
      */
     static constexpr const size_t MAX_NODE_ENTRY_COUNT {16};
 
+    /* A key for a an index entry */
     using Key = std::map<std::string, Blob>;
+    /* Specifications of the keys. It defines the number, the length and the
+     * serialization order of fields. */
+    using KeySpec = std::map<std::string, size_t>;
 
     using LookupCallback = std::function<void(std::vector<std::shared_ptr<Value>>& values, Prefix p)>;
     typedef void (*LookupCallbackRaw)(std::vector<std::shared_ptr<Value>>* values, Prefix* p, void *user_data);
@@ -162,8 +169,12 @@ public:
         };
     }
 
-    Pht(std::string name, std::shared_ptr<DhtRunner> dht)
-        : name_(INDEX_PREFIX + name), canary_(name_ + ".canary"), dht_(dht) { }
+    Pht(std::string name, KeySpec k_spec, std::shared_ptr<DhtRunner> dht)
+        : name_(INDEX_PREFIX + name), canary_(name_ + ".canary"), keySpec_(k_spec), dht_(dht)
+    {
+        if (k_spec.size() != 1)
+            throw std::invalid_argument("PHT only supports unidimensional data.");
+    }
     virtual ~Pht () { }
 
     /**
@@ -295,27 +306,39 @@ private:
         std::multimap<time_point, std::shared_ptr<Node>> leaves_;
     };
 
+    /**
+     * Performs a step in the lookup operation. Each steps are performed
+     * asynchronously.
+     */
+    void lookupStep(Prefix k, std::shared_ptr<int> lo, std::shared_ptr<int> hi,
+            std::shared_ptr<std::vector<std::shared_ptr<Value>>> vals, LookupCallback cb,
+            DoneCallbackSimple done_cb, std::shared_ptr<unsigned> max_common_prefix_len,
+            int start = -1, bool all_values = false);
+
     /**
      * Linearizes the key into a unidimensional key. A pht only takes
      * unidimensional key.
      *
      * @param Key  The initial key.
      *
-     * @return return The linearized key.
+     * @return the prefix of the linearized key.
      */
-    static Prefix linearize(Key k) {
-        if (k.size() != 1) { throw std::invalid_argument("PHT only supports unidimensional data."); }
-        return k.begin()->second;
+    virtual Prefix linearize(Key k) const {
+        if (not validKey(k)) { throw std::invalid_argument(INVALID_KEY); }
+        return Blob {k.begin()->second.begin(), k.begin()->second.begin() + keySpec_.begin()->second};
     };
 
     /**
-     * Performs a step in the lookup operation. Each steps are performed
-     * asynchronously.
+     * Tells if the key is valid according to the key spec.
      */
-    void lookupStep(Prefix k, std::shared_ptr<int> lo, std::shared_ptr<int> hi,
-            std::shared_ptr<std::vector<std::shared_ptr<Value>>> vals, LookupCallback cb,
-            DoneCallbackSimple done_cb, std::shared_ptr<unsigned> max_common_prefix_len,
-            int start = -1, bool all_values = false);
+    bool validKey(const Key& k) const {
+        return k.size() == keySpec_.size() and
+            std::equal(k.begin(), k.end(), keySpec_.begin(),
+                [&](const Key::value_type& key, const KeySpec::value_type& key_spec) {
+                    return key.first == key_spec.first;
+                }
+            );
+    }
 
     /**
      * Updates the canary token on the node responsible for the specified
@@ -325,6 +348,7 @@ private:
 
     const std::string name_;
     const std::string canary_;
+    const KeySpec keySpec_;
     Cache cache_;
     std::shared_ptr<DhtRunner> dht_;
 };
diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp
index 2dabb2cbca6fc9545d8d86f87cf7abc1b829634e..f8a6613bc3d346bbbeba27c98815911b6ab3b192 100644
--- a/tools/dhtnode.cpp
+++ b/tools/dhtnode.cpp
@@ -73,7 +73,7 @@ void print_help() {
               << std::endl;
 }
 
-void cmd_loop(std::shared_ptr<DhtRunner>& dht, std::map<std::string, dht::indexation::Pht> indexes, dht_params& params)
+void cmd_loop(std::shared_ptr<DhtRunner>& dht, std::map<std::string, indexation::Pht> indexes, dht_params& params)
 {
     print_node_info(dht, params);
     std::cout << " (type 'h' or 'help' for a list of possible commands)" << std::endl << std::endl;
@@ -161,11 +161,23 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, std::map<std::string, dht::indexa
         if (op == "il" or op == "ii") {
             // Pht syntax
             iss >> index >> keystr;
+            auto new_index = std::find_if(indexes.begin(), indexes.end(),
+                    [&](std::pair<const std::string, indexation::Pht>& i) {
+                        return i.first == index;
+                    }) == indexes.end();
             if (not index.size()) {
                 std::cout << "You must enter the index name." << std::endl;
                 continue;
-            } else {
-                indexes.emplace(index, dht::indexation::Pht {index, dht});
+            } else if (new_index) {
+                using namespace dht::indexation;
+                try {
+                    auto key = createPhtKey(parseStringMap(keystr));
+                    Pht::KeySpec ks;
+                    std::transform(key.begin(), key.end(), std::inserter(ks, ks.end()), [](Pht::Key::value_type& f) {
+                        return std::make_pair(f.first, f.second.size());
+                    });
+                    indexes.emplace(index, Pht {index, std::move(ks), dht});
+                } catch (std::invalid_argument& e) { std::cout << e.what() << std::endl; }
             }
         }
         else {
@@ -265,25 +277,30 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, std::map<std::string, dht::indexa
         else if (op == "il") {
             std::string exact_match;
             iss >> exact_match;
-            indexes.at(index).lookup(createPhtKey(parseStringMap(keystr)),
-                [=](std::vector<std::shared_ptr<indexation::Value>>& vals, indexation::Prefix p) {
-                    std::cout << "Pht::lookup: at prefix \"" << p.toString() << "\"" << ", hash is " << p.hash() << std::endl;
-                    for (auto v : vals) {
-                        std::cout << "Pht::lookup: found hash" << std::endl
-                                  << "\t" << v->first << "[vid: " << v->second << "]" << std::endl;
-                    }
-                    std::cout << "Pht::lookup: done." << std::endl;
-                },
-                [start](bool ok) {
-                    if (not ok) {
-                        std::cout << "Pht::lookup: dht Get failed." << std::endl;
-                    }
-
-                    auto end = std::chrono::high_resolution_clock::now();
-                    std::cout << "Pht::lookup: took " << print_dt(end-start) << "s)" << std::endl;
-
-                }, exact_match.size() != 0 and exact_match == "false" ? false : true
-            );
+            try {
+                auto key = createPhtKey(parseStringMap(keystr));
+                std::cout << "Pht::lookup(key=\"" << indexes.at(index).linearize(key).toString() << "\")" << std::endl;
+                indexes.at(index).lookup(key,
+                    [=](std::vector<std::shared_ptr<indexation::Value>>& vals, indexation::Prefix p) {
+                        if (vals.empty())
+                            return;
+                        std::cout << "Pht::lookup: found entries!" << std::endl
+                                  << "   prefix: \"" << p.toString() << "\"" << std::endl
+                                  << "   hash: " << p.hash() << std::endl;
+                        std::cout << "   entries:" << std::endl;
+                        for (auto v : vals)
+                             std::cout << "      " << v->first.toString() << "[vid: " << v->second << "]" << std::endl;
+                    },
+                    [start](bool ok) {
+                        auto end = std::chrono::high_resolution_clock::now();
+                        std::cout << "Pht::lookup: " << (ok ? "done." : "failed.")
+                                  << " took " << print_dt(end-start) << "s)" << std::endl;
+
+                    }, exact_match.size() != 0 and exact_match == "false" ? false : true
+                );
+            }
+            catch (std::invalid_argument& e) { std::cout << e.what() << std::endl; }
+            catch (std::out_of_range& e) { }
         }
         else if (op == "ii") {
             iss >> idstr;
@@ -292,15 +309,22 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, std::map<std::string, dht::indexa
                 continue;
 
             indexation::Value v {h, 0};
-            indexes.at(index).insert(createPhtKey(parseStringMap(keystr)), v,
-                [=](bool success) {
-                    if (not success) {
-                        std::cout << "Pht::insert: failed." << std::endl;
-                        return;
+            try {
+                auto key = createPhtKey(parseStringMap(keystr));
+                std::cout << "Pht::insert(key=\"" << indexes.at(index).linearize(key).toString()
+                          << "\", " << h.toString() << ")" << std::endl;
+                indexes.at(index).insert(key, v,
+                    [=](bool success) {
+                        if (not success) {
+                            std::cout << "Pht::insert: failed." << std::endl;
+                            return;
+                        }
+                        std::cout << "Pht::insert: done." << std::endl;
                     }
-                    std::cout << "Pht::insert: done." << std::endl;
-                }
-            );
+                );
+            }
+            catch (std::invalid_argument& e) { std::cout << e.what() << std::endl; }
+            catch (std::out_of_range& e) { }
         }
     }
 
@@ -314,7 +338,7 @@ main(int argc, char **argv)
         throw std::runtime_error(std::string("Error initializing GnuTLS: ")+gnutls_strerror(rc));
 
     auto dht = std::make_shared<DhtRunner>();
-    std::map<std::string, dht::indexation::Pht> indexes;
+    std::map<std::string, indexation::Pht> indexes;
 
     try {
         auto params = parseArgs(argc, argv);