diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php
index 3b60d528bf..fee918aa48 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php
@@ -365,8 +365,7 @@ public function resetImplementations() {
    * {@inheritdoc}
    */
   public function implementsHook($module, $hook) {
-    $function = $module . '_' . $hook;
-    if (function_exists($function)) {
+    if (self::callableExists($module, $hook)) {
       return TRUE;
     }
     // If the hook implementation does not exist, check whether it lives in an
@@ -374,7 +373,7 @@ public function implementsHook($module, $hook) {
     $hook_info = $this->getHookInfo();
     if (isset($hook_info[$hook]['group'])) {
       $this->loadInclude($module, 'inc', $module . '.' . $hook_info[$hook]['group']);
-      if (function_exists($function)) {
+      if (function_exists($module . '_' . $hook)) {
         return TRUE;
       }
     }
@@ -388,8 +387,8 @@ public function invoke($module, $hook, array $args = []) {
     if (!$this->implementsHook($module, $hook)) {
       return;
     }
-    $function = $module . '_' . $hook;
-    return call_user_func_array($function, $args);
+    $callable = self::getCallable($module, $hook);
+    return call_user_func_array($callable, $args);
   }
 
   /**
@@ -399,8 +398,8 @@ public function invokeAll($hook, array $args = []) {
     $return = [];
     $implementations = $this->getImplementations($hook);
     foreach ($implementations as $module) {
-      $function = $module . '_' . $hook;
-      $result = call_user_func_array($function, $args);
+      $callable = self::getCallable($module, $hook);
+      $result = call_user_func_array($callable, $args);
       if (isset($result) && is_array($result)) {
         $return = NestedArray::mergeDeep($return, $result);
       }
@@ -484,7 +483,7 @@ public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
         // function_exists(), since $this->getImplementations() returns only
         // modules with implementations.
         foreach ($modules as $module) {
-          $this->alterFunctions[$cid][] = $module . '_' . $hook;
+          $this->alterFunctions[$cid][] = $this->getCallable($module, $hook);
         }
       }
       else {
@@ -520,15 +519,13 @@ public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
         foreach ($modules as $module) {
           // Since $modules is a merged array, for any given module, we do not
           // know whether it has any particular implementation, so we need a
-          // function_exists().
-          $function = $module . '_' . $hook;
-          if (function_exists($function)) {
-            $this->alterFunctions[$cid][] = $function;
+          // to check if callable exists.
+          if ($callable = self::getCallable($module, $hook)) {
+            $this->alterFunctions[$cid][] = $callable;
           }
           foreach ($extra_types as $extra_type) {
-            $function = $module . '_' . $extra_type . '_alter';
-            if (function_exists($function)) {
-              $this->alterFunctions[$cid][] = $function;
+            if ($callable = self::getCallable($module, $extra_type . '_alter')) {
+              $this->alterFunctions[$cid][] = $callable;
             }
           }
         }
@@ -630,6 +627,9 @@ protected function buildImplementationInfo($hook) {
       if (function_exists($module . '_' . $hook)) {
         $implementations[$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
       }
+      elseif(class_exists($class = self::buildClassName($module, $hook))) {
+        $implementations[$module] = $class;
+      }
     }
     // Allow modules to change the weight of specific implementations, but avoid
     // an infinite loop.
@@ -643,11 +643,11 @@ protected function buildImplementationInfo($hook) {
       foreach (array_diff_assoc($implementations, $implementations_before) as $module => $group) {
         // If an implementation of hook_module_implements_alter() changed or
         // added a group, the respective file needs to be included.
-        if ($group) {
+        if ($group && $group[0] != '\\') {
           $this->loadInclude($module, 'inc', "$module.$group");
         }
         // If a new implementation was added, verify that the function exists.
-        if (!function_exists($module . '_' . $hook)) {
+        if (!self::callableExists($module, $hook)) {
           throw new \RuntimeException("An invalid implementation {$module}_{$hook} was added by hook_module_implements_alter()");
         }
       }
@@ -682,7 +682,7 @@ protected function verifyImplementations(&$implementations, $hook) {
       // function exists on each request to avoid undefined function errors.
       // Since ModuleHandler::implementsHook() may needlessly try to
       // load the include file again, function_exists() is used directly here.
-      if (!function_exists($module . '_' . $hook)) {
+      if (!self::callableExists($module, $hook)) {
         // Clear out the stale implementation from the cache and force a cache
         // refresh to forget about no longer existing hook implementations.
         unset($implementations[$module]);
@@ -756,4 +756,35 @@ public function getName($module) {
     }
   }
 
+  /**
+   * Builds hook class name.
+   */
+  private function buildClassName($module, $hook) {
+    return '\Drupal\\' . $module . '\\Hook\\' . str_replace('_', '', ucwords($hook, ' _-'));
+  }
+
+  /**
+   * Returns hook callable.
+   */
+  private function getCallable($module, $hook) {
+    if (function_exists($function = $module . '_' . $hook)) {
+      return $function;
+    }
+    elseif (class_exists($class = self::buildClassName($module, $hook))) {
+      if (is_subclass_of($class, 'Drupal\Core\DependencyInjection\ContainerInjectionInterface')) {
+        return $class::create(\Drupal::getContainer());
+      }
+      else {
+        return new $class;
+      }
+    }
+  }
+
+  /**
+   * Checks if callable exists.
+   */
+  private function callableExists($module, $hook) {
+    return function_exists($module . '_' . $hook) || class_exists(self::buildClassName($module, $hook));
+  }
+
 }
