diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index fd0ae33..0807ef7 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -2448,7 +2448,7 @@ function request_path() {
  * In menu callback functions, attempt to use named arguments. See the explanation
  * in menu.inc for how to construct callbacks that take arguments. When attempting
  * to use this function to load an element from the current path, e.g. loading the
- * node on a node page, please use menu_get_object() instead.
+ * node on a node page, please use $context[...] instead.
  *
  * @param $index
  *   The index of the component, where each component is separated by a '/'
diff --git a/includes/menu.inc b/includes/menu.inc
index 3e775db..6942ab5 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -472,6 +472,33 @@ function menu_get_item($path = NULL, $router_item = NULL) {
   return $router_items[$path];
 }
 
+function menu_set_context(array $router_item) {
+  $position = NULL;
+  for ($offset = 0 ; $offset < $router_item['number_parts'] ; $offset++) {
+    if (is_numeric($router_item['original_map'][$offset])) {
+      $position = $offset;
+      break;
+    }
+  }
+  $base_context = drupal_get_context();
+  if (isset($position) && isset($router_item['load_functions'][$position])
+    && !empty($router_item['map'][$position])) {
+    $entity_type = drupal_substr($router_item['load_functions'][$position], 0, -5);
+    if (isset($base_context->handlerClasses[$entity_type])) {
+      $context = $base_context->addLayer();
+      $context[$entity_type] = $router_item['map'][$position];
+      $tracker = $context->lock();
+      unset($tracker->context); // ugly hack: prevent destructor from releasing context
+    }
+    else {
+      drupal_set_message(t('No handler class for %entity_type.', array(
+        '%entity_type' => $entity_type,
+      )));
+    }
+  }
+  // dsm(get_defined_vars(), __FUNCTION__ . ' ' . REQUEST_TIME);
+}
+
 /**
  * Execute the page callback associated with the current path.
  *
@@ -500,6 +527,7 @@ function menu_execute_active_handler($path = NULL, $deliver = TRUE) {
         if ($router_item['include_file']) {
           require_once DRUPAL_ROOT . '/' . $router_item['include_file'];
         }
+        menu_set_context($router_item);
         $page_callback_result = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
       }
       else {
@@ -740,7 +768,7 @@ function _menu_translate(&$router_item, $map, $to_arg = FALSE) {
     // Fill in missing path elements, such as the current uid.
     _menu_link_map_translate($map, $router_item['to_arg_functions']);
   }
-  // The $path_map saves the pieces of the path as strings, while elements in
+  // The $path_map saves the pieces of the< path as strings, while elements in
   // $map may be replaced with loaded objects.
   $path_map = $map;
   if (!empty($router_item['load_functions']) && !_menu_load_objects($router_item, $map)) {
@@ -951,7 +979,7 @@ function _menu_link_translate(&$item, $translate = FALSE) {
  * @param $path
  *   See menu_get_item() for more on this. Defaults to the current path.
  */
-function menu_get_object($type = 'node', $position = 1, $path = NULL) {
+function Zmenu_get_object($type = 'node', $position = 1, $path = NULL) {
   $router_item = menu_get_item($path);
   if (isset($router_item['load_functions'][$position]) && !empty($router_item['map'][$position]) && $router_item['load_functions'][$position] == $type . '_load') {
     return $router_item['map'][$position];
diff --git a/includes/theme.inc b/includes/theme.inc
index 6c2b640..4debaee 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -2185,7 +2185,8 @@ function template_preprocess_html(&$variables) {
   }
 
   // If on an individual node page, add the node type to body classes.
-  if ($node = menu_get_object()) {
+  $context = drupal_get_context();
+  if ($node = $context['node']) {
     $variables['classes_array'][] = drupal_html_class('node-type-' . $node->type);
   }
 
@@ -2275,7 +2276,8 @@ function template_preprocess_page(&$variables) {
   $variables['site_slogan']       = (theme_get_setting('toggle_slogan') ? filter_xss_admin(variable_get('site_slogan', '')) : '');
   $variables['tabs']              = menu_local_tabs();
 
-  if ($node = menu_get_object()) {
+  $context = drupal_get_context();
+  if ($node = $context['node']) {
     $variables['node'] = $node;
   }
 
diff --git a/modules/book/book.module b/modules/book/book.module
index beb1721..76fdc9a 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -249,7 +249,8 @@ function book_block_info() {
 function book_block_view($delta = '') {
   $block = array();
   $current_bid = 0;
-  if ($node = menu_get_object()) {
+  $context = drupal_get_context();
+  if ($node = $context['node']) {
     $current_bid = empty($node->book['bid']) ? 0 : $node->book['bid'];
   }
 
@@ -824,7 +825,8 @@ function book_node_view($node, $view_mode) {
  * viewing a book page.
  */
 function book_page_alter(&$page) {
-  if (($node = menu_get_object()) && !empty($node->book['bid'])) {
+  $context = drupal_get_context();
+  if (($node = $context['menu:object:node']) && !empty($node->book['bid'])) {
     $active_menus = menu_get_active_menu_names();
     $active_menus[] = $node->book['menu_name'];
     menu_set_active_menu_names($active_menus);
diff --git a/modules/node/node.module b/modules/node/node.module
index 1ecc093..5646b89 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1419,7 +1419,8 @@ function node_show($node, $message = FALSE) {
  *   A node object.
  */
 function node_is_page($node) {
-  $page_node = menu_get_object();
+  $context = drupal_get_context();
+  $page_node = $context['node'];
   return (!empty($page_node) ? $page_node->nid == $node->nid : FALSE);
 }
 
@@ -2389,7 +2390,8 @@ function node_block_list_alter(&$blocks) {
     $block_node_types[$record->module][$record->delta][$record->type] = TRUE;
   }
 
-  $node = menu_get_object();
+  $context = drupal_get_context();
+  $node = $context['node'];
   $node_types = node_type_get_types();
   if (arg(0) == 'node' && arg(1) == 'add' && arg(2)) {
     $node_add_arg = strtr(arg(2), '-', '_');
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index ab3e0fc..38cb778 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -860,7 +860,8 @@ function hook_ajax_render_alter($commands) {
  * @see drupal_render_page()
  */
 function hook_page_build(&$page) {
-  if (menu_get_object('node', 1)) {
+  $context = drupal_get_context();
+  if ($context['node']) {
     // We are on a node detail page. Append a standard disclaimer to the
     // content region.
     $page['content']['disclaimer'] = array(
diff --git a/modules/system/system.context.inc b/modules/system/system.context.inc
new file mode 100644
index 0000000..ac278ce
--- /dev/null
+++ b/modules/system/system.context.inc
@@ -0,0 +1,17 @@
+<?php
+class ContextHandlerEntity extends ContextHandlerAbstract {
+
+  /**
+   * Implements ContextHandlerInterface:getValue().
+   *
+   * Args is only valid if empty. Currently no valid value exists except empty.
+   *
+   * This function is not needed in the current implementation: whenever a
+   * context contains an entity value, it will be readily available without
+   * invoking the method, and whenever the method is invoked, there is no
+   * entity value to return.
+   */
+  public function getValue(array $args = array()) {
+    return;
+  }
+}
diff --git a/modules/system/system.info b/modules/system/system.info
index c394849..6382c63 100644
--- a/modules/system/system.info
+++ b/modules/system/system.info
@@ -8,6 +8,7 @@ files[] = system.mail.inc
 files[] = system.queue.inc
 files[] = system.tar.inc
 files[] = system.updater.inc
+files[] = system.context.inc
 files[] = system.test
 required = TRUE
 configure = admin/config/system
diff --git a/modules/system/system.module b/modules/system/system.module
index d754555..cb8801b 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -1925,8 +1925,15 @@ function system_context_init(DrupalContextInterface $butler) {
   $butler->registerHandler('http:get', 'ContextHandlerHttp', array('query' => 'GET'));
   $butler->registerHandler('http:post', 'ContextHandlerHttp', array('query' => 'POST'));
   $butler->registerHandler('http:header', 'ContextHandlerHeader');
-}
 
+  $entities = module_invoke_all('entity_info');
+  foreach ($entities as $entity_type => $entity) {
+    $uri_callback = isset($entity['uri callback']) ? $entity['uri callback'] : NULL;
+    if (function_exists($uri_callback)) {
+      $butler->registerHandler($entity_type, 'ContextHandlerEntity', array('entity' => $entity));
+    }
+  }
+}
 
 /**
  * Adds CSS and JavaScript files declared in module .info files.
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index eb81870..2edb3fe 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -801,7 +801,8 @@ function template_preprocess_taxonomy_term(&$variables) {
  *   A term object.
  */
 function taxonomy_term_is_page($term) {
-  $page_term = menu_get_object('taxonomy_term', 2);
+  $context = drupal_get_context();
+  $page_term = $context['taxonomy_term'];
   return (!empty($page_term) ? $page_term->tid == $term->tid : FALSE);
 }
 
