diff --git a/includes/menu.inc b/includes/menu.inc
index 8837101414c1a3126fdd75d9934ae7fabc622e77..d16f3005883ee5e542bc77fb17662139b9e05255 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -1854,7 +1854,7 @@ function menu_local_tasks($level = 0) {
  * @return
  *   A list of menu router items that are local tasks for the passed in path.
  *
- * @see system_preprocess()
+ * @see contextual_links_preprocess()
  */
 function menu_contextual_links($module, $parent_path, $args) {
   static $path_empty = array();
diff --git a/modules/block/block.tpl.php b/modules/block/block.tpl.php
index c77d57e323d26f1d7d4ccada89a8a946a58880f7..beb54687b11fd32e99c5a9f3caf670dd77c2599b 100644
--- a/modules/block/block.tpl.php
+++ b/modules/block/block.tpl.php
@@ -38,7 +38,7 @@
 ?>
 <div id="block-<?php print $block->module . '-' . $block->delta; ?>" class="<?php print $classes; ?>"<?php print $attributes; ?>>
  
-<?php if ($contextual_links): ?>
+<?php if (!empty($contextual_links)): ?>
   <?php print render($contextual_links); ?>
 <?php endif; ?>
  
diff --git a/misc/contextual_links.css b/modules/contextual/contextual.css
similarity index 94%
rename from misc/contextual_links.css
rename to modules/contextual/contextual.css
index 4d2ac51e8635134196c7e7ed53f34230e0904428..eafc809da8b727c8e24d57189e7c9ccd5a64f839 100644
--- a/misc/contextual_links.css
+++ b/modules/contextual/contextual.css
@@ -26,7 +26,7 @@ html.js div.contextual-links-wrapper {
   display: block;
 }
 a.contextual-links-trigger {
-  background: transparent url(cog-select.png) no-repeat center center;
+  background: transparent url(images/cog-select.png) no-repeat center center;
   display: none;
   height: 20px;
   margin-top: 2px;
diff --git a/modules/contextual/contextual.info b/modules/contextual/contextual.info
new file mode 100644
index 0000000000000000000000000000000000000000..71f465bc1a75814b093092f908f41ba81e1e1375
--- /dev/null
+++ b/modules/contextual/contextual.info
@@ -0,0 +1,7 @@
+; $Id$
+name = Contextual links
+description = Provides contextual links to perform actions related to elements on a page.
+package = Core
+version = VERSION
+core = 7.x
+files[] = contextual.module
diff --git a/misc/contextual_links.js b/modules/contextual/contextual.js
similarity index 100%
rename from misc/contextual_links.js
rename to modules/contextual/contextual.js
diff --git a/modules/contextual/contextual.module b/modules/contextual/contextual.module
new file mode 100644
index 0000000000000000000000000000000000000000..f174047bed11f903d7092fa835795079be900609
--- /dev/null
+++ b/modules/contextual/contextual.module
@@ -0,0 +1,143 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Adds contextual links to perform actions related to elements on a page.
+ */
+
+/**
+ * Implements hook_permission().
+ */
+function contextual_permission() {
+  return array(
+    'access contextual links' => array(
+      'title' => t('Use contextual links'),
+      'description' => t('Use contextual links to perform actions related to elements on a page.'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_library().
+ */
+function contextual_library() {
+  $path = drupal_get_path('module', 'contextual');
+  $libraries['contextual-links'] = array(
+    'title' => 'Contextual links',
+    'website' => 'http://drupal.org/node/473268',
+    'version' => '1.0',
+    'js' => array(
+      $path . '/contextual.js' => array(),
+    ),
+    'css' => array(
+      $path . '/contextual.css' => array(),
+    ),
+  );
+  return $libraries;
+}
+
+/**
+ * Template variable preprocessor for contextual links.
+ *
+ * @see contextual_links_build()
+ */
+function contextual_preprocess(&$variables, $hook) {
+  static $hooks;
+
+  // Initialize the $contextual_links template variable.
+  $variables['contextual_links'] = array();
+
+  // Nothing to do here if the user is not permitted to access contextual links.
+  if (!user_access('access contextual links')) {
+    return;
+  }
+
+  if (!isset($hooks)) {
+    $hooks = theme_get_registry();
+  }
+
+  // Determine the primary theme function argument.
+  if (isset($hooks[$hook]['variables'])) {
+    $keys = array_keys($hooks[$hook]['variables']);
+    $key = $keys[0];
+  }
+  else {
+    $key = $hooks[$hook]['render element'];
+  }
+  if (isset($variables[$key])) {
+    $element = $variables[$key];
+  }
+
+  if (isset($element) && is_array($element) && !empty($element['#contextual_links'])) {
+    $variables['contextual_links'] = contextual_links_build($element);
+    if (!empty($variables['contextual_links'])) {
+      $variables['classes_array'][] = 'contextual-links-region';
+    }
+  }
+}
+
+/**
+ * Build a renderable array for contextual links.
+ *
+ * @param $element
+ *   A renderable array containing a #contextual_links property, which is a
+ *   keyed array. Each key is the name of the implementing module, and each
+ *   value is an array that forms the function arguments for
+ *   menu_contextual_links(). For example:
+ *   @code
+ *     array('#contextual_links' => array(
+ *       'block' => array('admin/structure/block/manage', array('system', 'navigation')),
+ *       'menu' => array('admin/structure/menu/manage', array('navigation')),
+ *     ))
+ *   @endcode
+ *
+ * @return
+ *   A renderable array representing contextual links.
+ *
+ * @see menu_contextual_links()
+ */
+function contextual_links_build($element) {
+  static $destination;
+
+  // Retrieve contextual menu links.
+  $items = array();
+  foreach ($element['#contextual_links'] as $module => $args) {
+    $items += menu_contextual_links($module, $args[0], $args[1]);
+  }
+
+  // Transform contextual links into parameters suitable for theme_link().
+  if (!isset($destination)) {
+    $destination = drupal_get_destination();
+  }
+
+  $links = array();
+  foreach ($items as $class => $item) {
+    $class = drupal_html_class($class);
+    $links[$class] = array(
+      'title' => $item['title'],
+      'href' => $item['href'],
+    );
+    // @todo theme_links() should *really* use the same parameters as l()...
+    if (!isset($item['localized_options']['query'])) {
+      $item['localized_options']['query'] = array();
+    }
+    $item['localized_options']['query'] += $destination;
+    $links[$class] += $item['localized_options'];
+  }
+  $build = array();
+  if ($links) {
+    $build = array(
+      '#prefix' => '<div class="contextual-links-wrapper">',
+      '#suffix' => '</div>',
+      '#theme' => 'links',
+      '#links' => $links,
+      '#attributes' => array('class' => array('contextual-links')),
+      '#attached' => array(
+        'library' => array(array('contextual', 'contextual-links')),
+      ),
+    );
+  }
+  return $build;
+}
+
diff --git a/misc/cog-select.png b/modules/contextual/images/cog-select.png
similarity index 100%
rename from misc/cog-select.png
rename to modules/contextual/images/cog-select.png
diff --git a/modules/node/node.tpl.php b/modules/node/node.tpl.php
index 34b0c4bf1b573151de1fb9f02767a309c4922b2c..6435cdf94e54bc26a2ea57b996d52553576a6189 100644
--- a/modules/node/node.tpl.php
+++ b/modules/node/node.tpl.php
@@ -75,7 +75,7 @@
 
   <?php print $user_picture; ?>
 
-  <?php if (!$page && $contextual_links): ?>
+  <?php if (!$page && !empty($contextual_links)): ?>
     <?php print render($contextual_links); ?>
   <?php endif; ?>
 
diff --git a/modules/system/system.module b/modules/system/system.module
index aacd5a35cac086cd13be731a946114b2a32d7e95..0493afea2ed188efdfbb00cef13f76aded28d961 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -226,10 +226,6 @@ function system_permission() {
     'access administration pages' => array(
       'title' => t('Use the administration pages and help'),
     ),
-    'access contextual links' => array(
-      'title' => t('Use contextual links'),
-      'description' => t('Use contextual links to perform actions related to elements on a page.'),
-    ),
     'access site in maintenance mode' => array(
       'title' => t('Use the site in maintenance mode'),
     ),
@@ -1102,19 +1098,6 @@ function system_library() {
     ),
   );
 
-  // Contextual links.
-  $libraries['contextual-links'] = array(
-    'title' => 'Contextual links',
-    'website' => 'http://drupal.org/node/473268',
-    'version' => '1.0',
-    'js' => array(
-      'misc/contextual_links.js' => array(),
-    ),
-    'css' => array(
-      'misc/contextual_links.css' => array(),
-    ),
-  );
-
   // Vertical Tabs.
   $libraries['vertical-tabs'] = array(
     'title' => 'Vertical Tabs',
@@ -3579,110 +3562,6 @@ function theme_system_settings_form($variables) {
   return drupal_render_children($variables['form']);
 }
 
-/**
- * Template variable preprocessor for contextual links.
- *
- * @see system_build_contextual_links()
- */
-function system_preprocess(&$variables, $hook) {
-  static $hooks;
-
-  // Initialize the $contextual_links template variable.
-  $variables['contextual_links'] = array();
-
-  // Nothing to do here if the user is not permitted to access contextual links.
-  if (!user_access('access contextual links')) {
-    return;
-  }
-
-  if (!isset($hooks)) {
-    $hooks = theme_get_registry();
-  }
-
-  // Determine the primary theme function argument.
-  if (isset($hooks[$hook]['variables'])) {
-    $keys = array_keys($hooks[$hook]['variables']);
-    $key = $keys[0];
-  }
-  else {
-    $key = $hooks[$hook]['render element'];
-  }
-  if (isset($variables[$key])) {
-    $element = $variables[$key];
-  }
-
-  if (isset($element) && is_array($element) && !empty($element['#contextual_links'])) {
-    $variables['contextual_links'] = system_build_contextual_links($element);
-    if (!empty($variables['contextual_links'])) {
-      $variables['classes_array'][] = 'contextual-links-region';
-    }
-  }
-}
-
-/**
- * Build a renderable array for contextual links.
- *
- * @param $element
- *   A renderable array containing a #contextual_links property, which is a
- *   keyed array. Each key is the name of the implementing module, and each
- *   value is an array that forms the function arguments for
- *   menu_contextual_links(). For example:
- *   @code
- *     array('#contextual_links' => array(
- *       'block' => array('admin/structure/block/manage', array('system', 'navigation')),
- *       'menu' => array('admin/structure/menu/manage', array('navigation')),
- *     ))
- *   @endcode
- *
- * @return
- *   A renderable array representing contextual links.
- *
- * @see menu_contextual_links()
- */
-function system_build_contextual_links($element) {
-  static $destination;
-
-  // Retrieve contextual menu links.
-  $items = array();
-  foreach ($element['#contextual_links'] as $module => $args) {
-    $items += menu_contextual_links($module, $args[0], $args[1]);
-  }
-
-  // Transform contextual links into parameters suitable for theme_link().
-  if (!isset($destination)) {
-    $destination = drupal_get_destination();
-  }
-
-  $links = array();
-  foreach ($items as $class => $item) {
-    $class = drupal_html_class($class);
-    $links[$class] = array(
-      'title' => $item['title'],
-      'href' => $item['href'],
-    );
-    // @todo theme_links() should *really* use the same parameters as l()...
-    if (!isset($item['localized_options']['query'])) {
-      $item['localized_options']['query'] = array();
-    }
-    $item['localized_options']['query'] += $destination;
-    $links[$class] += $item['localized_options'];
-  }
-  $build = array();
-  if ($links) {
-    $build = array(
-      '#prefix' => '<div class="contextual-links-wrapper">',
-      '#suffix' => '</div>',
-      '#theme' => 'links',
-      '#links' => $links,
-      '#attributes' => array('class' => array('contextual-links')),
-      '#attached' => array(
-        'library' => array(array('system', 'contextual-links')),
-      ),
-    );
-  }
-  return $build;
-}
-
 /**
  * Implements hook_admin_paths().
  */
diff --git a/profiles/default/default.info b/profiles/default/default.info
index aced644432a7f0e93f0f3f62aad80531a4502c32..a2b17aeb296d83b9a7515fb3261412dae1822a37 100644
--- a/profiles/default/default.info
+++ b/profiles/default/default.info
@@ -6,6 +6,7 @@ core = 7.x
 dependencies[] = block
 dependencies[] = color
 dependencies[] = comment
+dependencies[] = contextual
 dependencies[] = dashboard
 dependencies[] = help
 dependencies[] = image
diff --git a/themes/garland/block.tpl.php b/themes/garland/block.tpl.php
index 9474ba72a54185f46d54d3508faee0decf47a0c5..da147997e45123868c38056a202ac839748e63cb 100644
--- a/themes/garland/block.tpl.php
+++ b/themes/garland/block.tpl.php
@@ -3,7 +3,7 @@
 ?>
 <div id="block-<?php print $block->module . '-' . $block->delta; ?>" class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
 
-<?php if ($contextual_links): ?>
+<?php if (!empty($contextual_links)): ?>
   <?php print render($contextual_links); ?>
 <?php endif; ?>
 
diff --git a/themes/garland/node.tpl.php b/themes/garland/node.tpl.php
index 47f9cc97471134657a3fa1cd246357039a4e6ebb..4a2733f42ca96836db8646f7fb7c9e41a2d24381 100644
--- a/themes/garland/node.tpl.php
+++ b/themes/garland/node.tpl.php
@@ -3,7 +3,7 @@
 ?>
 <div id="node-<?php print $node->nid; ?>" class="<?php print $classes; ?>"<?php print $attributes; ?>>
 
-  <?php if (!$page && $contextual_links): ?>
+  <?php if (!$page && !empty($contextual_links)): ?>
     <?php print render($contextual_links); ?>
   <?php endif; ?>