Add support for service identification using the key_type typedef.
diff --git a/asio/include/asio/detail/impl/service_registry.hpp b/asio/include/asio/detail/impl/service_registry.hpp
index efa4733..bba1540 100644
--- a/asio/include/asio/detail/impl/service_registry.hpp
+++ b/asio/include/asio/detail/impl/service_registry.hpp
@@ -24,7 +24,7 @@
 Service& service_registry::use_service()
 {
   execution_context::service::key key;
-  init_key(key, Service::id);
+  init_key<Service>(key, 0);
   factory_type factory = &service_registry::create<Service, execution_context>;
   return *static_cast<Service*>(do_use_service(key, factory, &owner_));
 }
@@ -33,7 +33,7 @@
 Service& service_registry::use_service(io_context& owner)
 {
   execution_context::service::key key;
-  init_key(key, Service::id);
+  init_key<Service>(key, 0);
   factory_type factory = &service_registry::create<Service, io_context>;
   return *static_cast<Service*>(do_use_service(key, factory, &owner));
 }
@@ -42,7 +42,7 @@
 void service_registry::add_service(Service* new_service)
 {
   execution_context::service::key key;
-  init_key(key, Service::id);
+  init_key<Service>(key, 0);
   return do_add_service(key, new_service);
 }
 
@@ -50,13 +50,29 @@
 bool service_registry::has_service() const
 {
   execution_context::service::key key;
-  init_key(key, Service::id);
+  init_key<Service>(key, 0);
   return do_has_service(key);
 }
 
+template <typename Service>
+inline void service_registry::init_key(
+    execution_context::service::key& key, ...)
+{
+  init_key_from_id(key, Service::id);
+}
+
 #if !defined(ASIO_NO_TYPEID)
 template <typename Service>
 void service_registry::init_key(execution_context::service::key& key,
+    typename enable_if<
+      is_base_of<typename Service::key_type, Service>::value>::type*)
+{
+  key.type_info_ = &typeid(typeid_wrapper<Service>);
+  key.id_ = 0;
+}
+
+template <typename Service>
+void service_registry::init_key_from_id(execution_context::service::key& key,
     const service_id<Service>& /*id*/)
 {
   key.type_info_ = &typeid(typeid_wrapper<Service>);
diff --git a/asio/include/asio/detail/impl/service_registry.ipp b/asio/include/asio/detail/impl/service_registry.ipp
index 39dad4d..51dfa94 100644
--- a/asio/include/asio/detail/impl/service_registry.ipp
+++ b/asio/include/asio/detail/impl/service_registry.ipp
@@ -84,7 +84,7 @@
       services[i - 1]->notify_fork(fork_ev);
 }
 
-void service_registry::init_key(execution_context::service::key& key,
+void service_registry::init_key_from_id(execution_context::service::key& key,
     const execution_context::id& id)
 {
   key.type_info_ = 0;
diff --git a/asio/include/asio/detail/service_registry.hpp b/asio/include/asio/detail/service_registry.hpp
index 77af51b..babaec8 100644
--- a/asio/include/asio/detail/service_registry.hpp
+++ b/asio/include/asio/detail/service_registry.hpp
@@ -19,6 +19,7 @@
 #include <typeinfo>
 #include "asio/detail/mutex.hpp"
 #include "asio/detail/noncopyable.hpp"
+#include "asio/detail/type_traits.hpp"
 #include "asio/execution_context.hpp"
 
 #include "asio/detail/push_options.hpp"
@@ -75,15 +76,27 @@
   bool has_service() const;
 
 private:
+  // Initalise a service's key when the key_type typedef is not available.
+  template <typename Service>
+  static void init_key(execution_context::service::key& key, ...);
+
+#if !defined(ASIO_NO_TYPEID)
+  // Initalise a service's key when the key_type typedef is available.
+  template <typename Service>
+  static void init_key(execution_context::service::key& key,
+      typename enable_if<
+        is_base_of<typename Service::key_type, Service>::value>::type*);
+#endif // !defined(ASIO_NO_TYPEID)
+
   // Initialise a service's key based on its id.
-  ASIO_DECL static void init_key(
+  ASIO_DECL static void init_key_from_id(
       execution_context::service::key& key,
       const execution_context::id& id);
 
 #if !defined(ASIO_NO_TYPEID)
   // Initialise a service's key based on its id.
   template <typename Service>
-  static void init_key(execution_context::service::key& key,
+  static void init_key_from_id(execution_context::service::key& key,
       const service_id<Service>& /*id*/);
 #endif // !defined(ASIO_NO_TYPEID)
 
diff --git a/asio/include/asio/detail/type_traits.hpp b/asio/include/asio/detail/type_traits.hpp
index e7e65a8..f7afda6 100644
--- a/asio/include/asio/detail/type_traits.hpp
+++ b/asio/include/asio/detail/type_traits.hpp
@@ -24,6 +24,7 @@
 # include <boost/type_traits/conditional.hpp>
 # include <boost/type_traits/decay.hpp>
 # include <boost/type_traits/integral_constant.hpp>
+# include <boost/type_traits/is_base_of.hpp>
 # include <boost/type_traits/is_class.hpp>
 # include <boost/type_traits/is_const.hpp>
 # include <boost/type_traits/is_convertible.hpp>
@@ -44,6 +45,7 @@
 using std::enable_if;
 using std::false_type;
 using std::integral_constant;
+using std::is_base_of;
 using std::is_class;
 using std::is_const;
 using std::is_convertible;
@@ -61,6 +63,7 @@
 using boost::decay;
 using boost::false_type;
 using boost::integral_constant;
+using boost::is_base_of;
 using boost::is_class;
 using boost::is_const;
 using boost::is_convertible;
diff --git a/asio/include/asio/impl/execution_context.hpp b/asio/include/asio/impl/execution_context.hpp
index 06c64ad..69b9604 100644
--- a/asio/include/asio/impl/execution_context.hpp
+++ b/asio/include/asio/impl/execution_context.hpp
@@ -28,7 +28,6 @@
 {
   // Check that Service meets the necessary type requirements.
   (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
-  (void)static_cast<const execution_context::id*>(&Service::id);
 
   return e.service_registry_->template use_service<Service>();
 }
@@ -83,7 +82,6 @@
 {
   // Check that Service meets the necessary type requirements.
   (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
-  (void)static_cast<const execution_context::id*>(&Service::id);
 
   e.service_registry_->template add_service<Service>(svc);
 }
@@ -93,7 +91,6 @@
 {
   // Check that Service meets the necessary type requirements.
   (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
-  (void)static_cast<const execution_context::id*>(&Service::id);
 
   return e.service_registry_->template has_service<Service>();
 }
diff --git a/asio/src/examples/cpp11/executors/pipeline.cpp b/asio/src/examples/cpp11/executors/pipeline.cpp
index 168fbf3..86bf860 100644
--- a/asio/src/examples/cpp11/executors/pipeline.cpp
+++ b/asio/src/examples/cpp11/executors/pipeline.cpp
@@ -29,7 +29,7 @@
   class thread_bag : public execution_context::service
   {
   public:
-    static execution_context::id id;
+    typedef thread_bag key_type;
 
     explicit thread_bag(execution_context& ctx)
       : execution_context::service(ctx)
@@ -101,8 +101,6 @@
   }
 };
 
-execution_context::id thread_executor::thread_bag::id;
-
 // Base class for all thread-safe queue implementations.
 class queue_impl_base
 {
diff --git a/asio/src/examples/cpp14/executors/pipeline.cpp b/asio/src/examples/cpp14/executors/pipeline.cpp
index 4ee372e..12c2bef 100644
--- a/asio/src/examples/cpp14/executors/pipeline.cpp
+++ b/asio/src/examples/cpp14/executors/pipeline.cpp
@@ -24,7 +24,7 @@
   class thread_bag : public execution_context::service
   {
   public:
-    static execution_context::id id;
+    typedef thread_bag key_type;
 
     explicit thread_bag(execution_context& ctx)
       : execution_context::service(ctx)
@@ -96,8 +96,6 @@
   }
 };
 
-execution_context::id thread_executor::thread_bag::id;
-
 // Base class for all thread-safe queue implementations.
 class queue_impl_base
 {