diff --git admin_menu.api.php admin_menu.api.php
index 4ca7a65..44a5a1e 100644
--- admin_menu.api.php
+++ admin_menu.api.php
@@ -7,6 +7,42 @@
  */
 
 /**
+ * Provide expansion arguments for dynamic menu items, i.e. menu paths
+ * containing one or more %placeholders.
+ *
+ * The map items must be keyed by the dynamic path to expand. Each map item may
+ * have the following properties:
+ *
+ * - parent: The parent menu path to link the expanded items to.
+ * - arguments: An array of argument sets that will be used in the
+ *   expansion. Each set consists of an array of one or more placeholders with
+ *   an array of possible expansions as value. Upon expansion, each argument
+ *   is combined with every other argument from the set (ie., the cartesian
+ *   product of all arguments is created). The expansion values may be empty,
+ *   that is, you don't need to insert logic to skip map items for which no
+ *   values exist, since admin menu will take care of that.
+ * - hide: (optional) Used to hide another menu item, usually a superfluous
+ *   "List" item.
+ *
+ * @see admin_menu.map.inc
+ */
+function hook_admin_menu_map() {
+  // Expand content types in Structure >> Content types.
+  // The key denotes the dynamic path to expand to multiple menu items.
+  $map['admin/structure/types/manage/%node_type'] = array(
+    // Link generated items directly to the "Content types" item, and hide the
+    // "List" item.
+    'parent' => 'admin/structure/types',
+    'hide' => 'admin/structure/types/list',
+    // Create expansion arguments for the %node_type placeholder.
+    'arguments' => array(
+      array('%node_type' => array_keys(node_type_get_types())),
+    ),
+  );
+  return $map;
+}
+
+/**
  * Alter content in Administration menu bar before it is rendered.
  *
  * @param $content
diff --git admin_menu.inc admin_menu.inc
index 02320b1..72736bd 100644
--- admin_menu.inc
+++ admin_menu.inc
@@ -7,6 +7,327 @@
  */
 
 /**
+ * Build the full administration menu tree from static and expanded dynamic items.
+ *
+ * @param $menu_name
+ *   The menu name to use as base for the tree.
+ */
+function admin_menu_tree($menu_name) {
+  // Get placeholder expansion arguments from hook_admin_menu_map()
+  // implementations.
+  module_load_include('inc', 'admin_menu', 'admin_menu.map');
+  $expand_map = module_invoke_all('admin_menu_map');
+  // Allow modules to alter the expansion map.
+  drupal_alter('admin_menu_map', $expand_map);
+
+  $new_map = array();
+  $hidden = array();
+  foreach ($expand_map as $path => $data) {
+    // Convert named placeholders to anonymous placeholders, since the menu
+    // system stores paths using anonymous placeholders.
+    // @todo Why specify named placeholders in the first place then?
+    $replacements = array_fill_keys(array_keys($data['arguments'][0]), '%');
+    $data['parent'] = strtr($data['parent'], $replacements);
+    $new_map[strtr($path, $replacements)] = $data;
+
+    // Collect paths to hide.
+    if (isset($data['hide'])) {
+      $hidden[strtr($data['hide'], $replacements)] = 1;
+    }
+  }
+  $expand_map = $new_map;
+  unset($new_map);
+
+  // Retrieve dynamic menu link tree for the expansion mappings.
+  $tree_dynamic = admin_menu_tree_dynamic($expand_map);
+
+  // Merge local tasks with static menu tree.
+  $tree = menu_tree_all_data($menu_name);
+  admin_menu_merge_tree($tree, $tree_dynamic, array(), $hidden);
+
+  return $tree;
+}
+
+/**
+ * Load menu link trees for router paths containing dynamic arguments.
+ *
+ * @param $expand_map
+ *   An array containing menu router path placeholder expansion argument
+ *   mappings.
+ *
+ * @return
+ *   An associative array whose keys are the parent paths of the menu router
+ *   paths given in $expand_map as well as the parent paths of any child link
+ *   deeper down the tree. The parent paths are used in admin_menu_merge_tree()
+ *   to check whether anything needs to be merged.
+ *
+ * @see hook_admin_menu_map()
+ */
+function admin_menu_tree_dynamic(array $expand_map) {
+  $p_columns = array();
+  for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
+    $p_columns[] = 'p' . $i;
+  }
+
+  // Fetch p* columns for all router paths to expand.
+  $router_paths = array_keys($expand_map);
+  $plids = db_select('menu_links', 'ml')
+    ->fields('ml', $p_columns)
+    ->condition('router_path', $router_paths)
+    ->execute()
+    ->fetchAll(PDO::FETCH_ASSOC);
+
+  // Unlikely, but possible.
+  if (empty($plids)) {
+    return array();
+  }
+
+  // Use queried plid columns to query sub-trees for the router paths.
+  $query = db_select('menu_links', 'ml');
+  $query->join('menu_router', 'm', 'ml.router_path = m.path');
+  $query
+    ->fields('ml')
+    ->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), drupal_schema_fields_sql('menu_links')));
+
+  // The retrieved menu link trees have to be ordered by depth, so parents
+  // always come before their children for the storage logic below.
+  // @todo Order by 'fit' or 'depth' instead for parent path handling below?
+  foreach ($p_columns as $column) {
+    $query->orderBy($column, 'ASC');
+  }
+
+  $db_or = db_or();
+  foreach ($plids as $path_plids) {
+    $db_and = db_and();
+    // Skip 0 (zero) columns.
+    foreach (array_filter($path_plids) as $column => $plid) {
+      $db_and->condition($column, $plid);
+    }
+    $db_or->condition($db_and);
+  }
+  $query->condition($db_or);
+  $result = $query
+    ->execute()
+    ->fetchAllAssoc('mlid', PDO::FETCH_ASSOC);
+
+  // Store dynamic links grouped by parent path for later merging and assign
+  // placeholder expansion arguments.
+  $tree_dynamic = array();
+  foreach ($result as $mlid => $link) {
+    // If contained in $expand_map, then this is a (first) parent, and we need
+    // to store by the defined 'parent' path for later merging, as well as
+    // provide the expansion map arguments to apply to the dynamic tree.
+    if (isset($expand_map[$link['path']])) {
+      $parent_path = $expand_map[$link['path']]['parent'];
+      $link['expand_map'] = $expand_map[$link['path']]['arguments'];
+    }
+    // Otherwise, just store this link keyed by its parent path; the expand_map
+    // is automatically derived from parent paths.
+    else {
+      $parent_path = $result[$link['plid']]['path'];
+    }
+
+    $tree_dynamic[$parent_path][] = $link;
+  }
+
+  return $tree_dynamic;
+}
+
+/**
+ * Walk through the entire menu tree and merge in expanded dynamic menu links.
+ *
+ * @param &$tree
+ *   A menu tree structure as returned by menu_tree_all_data().
+ * @param $tree_dynamic
+ *   A dynamic menu tree structure as returned by admin_menu_tree_dynamic().
+ * @param $expand_map
+ *   @todo Rename this argument, it's not the same $expand_map like elsewhere.
+ *   Placeholder expansion arguments.
+ * @param $hidden
+ *   An array containing links to hide, keyed by path.
+ *
+ * @see hook_admin_menu_map()
+ * @see menu_tree_all_data()
+ * @see admin_menu_tree_dynamic()
+ */
+function admin_menu_merge_tree(array &$tree, array $tree_dynamic, array $expand_map, array $hidden) {
+  foreach ($tree as $key => $data) {
+    $path = $data['link']['router_path'];
+
+    // Recurse into regular menu tree.
+    if ($tree[$key]['below']) {
+      admin_menu_merge_tree($tree[$key]['below'], $tree_dynamic, $expand_map, $hidden);
+    }
+    // Hide link if requested, but only if there is no dynamic tree data for it.
+    elseif (isset($hidden[$path]) && !isset($tree_dynamic[$path])) {
+      $tree[$key]['link']['access'] = FALSE;
+      continue;
+    }
+    // Nothing to merge, if this parent path is not in our dynamic tree.
+    if (!isset($tree_dynamic[$path])) {
+      continue;
+    }
+
+    foreach ($tree_dynamic[$path] as $link) {
+      // If the local task has custom placeholder expansion arguments set,
+      // merge them with parent arguments.
+      if (isset($link['expand_map'])) {
+        $expand_map = array_merge($expand_map, $link['expand_map']);
+      }
+
+      // Set up path arguments map; depends on whether the item is dynamic
+      // (contains placeholders) or not.
+      if (strpos($link['path'], '%') === FALSE) {
+        echo "<pre>"; var_dump("IN"); echo "</pre>\n";
+        // Build static item and subtree.
+        $map = explode('/', $link['path']);
+        $item = admin_menu_translate($link, $map);
+        admin_menu_merge_tree($item, $tree_dynamic, $expand_map, $hidden);
+        $tree[$key]['below'] += $item;
+      }
+      else {
+        // Drop dynamic items without expansion parameters.
+        if (empty($expand_map)) {
+          continue;
+        }
+
+        // Expand anonymous to named placeholders.
+        // @see _menu_load_objects()
+        $active = '';
+        $path = explode('/', $link['path']);
+        $load_functions = unserialize($link['load_functions']);
+        foreach ($load_functions as $index => $function) {
+          if ($function) {
+            if (is_array($function)) {
+              list($function,) = each($function);
+            }
+            // Add the loader function name minus "_load".
+            $placeholder = '%' . substr($function, 0, -5);
+            $path[$index] = $placeholder;
+          }
+        }
+        $path = implode('/', $path);
+
+        // Create new menu items using expansion arguments.
+        foreach ($expand_map as $arguments) {
+          // Create the cartesian product for all arguments and create new
+          // menu items for each generated combination thereof.
+          foreach (admin_menu_expand_args($arguments) as $replacements) {
+            $map = explode('/', strtr($path, $replacements));
+            $item = admin_menu_translate($link, $map);
+            // Build subtree using current replacement arguments.
+            // @todo Avoid rebuilding this for each item.
+            $current_map = array();
+            foreach ($replacements as $placeholder => $value) {
+              $current_map[$placeholder] = array($value);
+            }
+            admin_menu_merge_tree($item, $tree_dynamic, array($current_map), $hidden);
+            $tree[$key]['below'] += $item;
+          }
+        }
+      }
+    }
+    // Sort new subtree items.
+    ksort($tree[$key]['below']);
+  }
+}
+
+/**
+ * Create a menu item suitable for rendering.
+ *
+ * @param $router_item
+ *   A menu router item.
+ * @param $map
+ *   A path map with placeholders replaced.
+ */
+function admin_menu_translate($router_item, $map) {
+  _menu_translate($router_item, $map, TRUE);
+
+  // Run through hook_translated_menu_link_alter() to add devel information,
+  // if configured.
+  $router_item['menu_name'] = 'management';
+  admin_menu_translated_menu_link_alter($router_item, NULL);
+
+  if ($router_item['access']) {
+    // Turn local task menu callbacks into regular menu items, otherwise they
+    // won't be visible.
+    if ($router_item['type'] == MENU_CALLBACK) {
+      $router_item['type'] = MENU_NORMAL_ITEM;
+    }
+    // Fill in pseudo menu link values for rendering later.
+    $router_item['router_path'] = $router_item['path'];
+    $router_item['mlid'] = $router_item['href'];
+    // @todo Strip potential HTML from titles?
+    $router_item['title'] = strip_tags($router_item['title']);
+
+    $key = (50000 + $router_item['weight']) . ' ' . $router_item['title'] . ' ' . $router_item['mlid'];
+    return array($key => array(
+      'link' => $router_item,
+      'below' => array(),
+    ));
+  }
+
+  return array();
+}
+
+/**
+ * Create the cartesian product of multiple varying sized argument arrays.
+ *
+ * @param $arguments
+ *   A two dimensional array of arguments.
+ *
+ * @see hook_admin_menu_map()
+ */
+function admin_menu_expand_args($arguments) {
+  $replacements = array();
+
+  // Initialize line cursors, move out array keys (placeholders) and assign
+  // numeric keys instead.
+  $i = 0;
+  $placeholders = array();
+  $new_arguments = array();
+  foreach ($arguments as $placeholder => $values) {
+    // Skip empty arguments.
+    if (empty($values)) {
+      continue;
+    }
+    $cursor[$i] = 0;
+    $placeholders[$i] = $placeholder;
+    $new_arguments[$i] = $values;
+    $i++;
+  }
+  $arguments = $new_arguments;
+  unset($new_arguments);
+
+  if ($rows = count($arguments)) {
+    do {
+      // Collect current argument from each row.
+      $row = array();
+      for ($i = 0; $i < $rows; ++$i) {
+        $row[$placeholders[$i]] = $arguments[$i][$cursor[$i]];
+      }
+      $replacements[] = $row;
+
+      // Increment cursor position.
+      $j = $rows - 1;
+      $cursor[$j]++;
+      while (!array_key_exists($cursor[$j], $arguments[$j])) {
+        // No more arguments left: reset cursor, go to next line and increment
+        // that cursor instead. Repeat until argument found or out of rows.
+        $cursor[$j] = 0;
+        if (--$j < 0) {
+          // We're done.
+          break 2;
+        }
+        $cursor[$j]++;
+      }
+    } while (1);
+  }
+
+  return $replacements;
+}
+
+/**
  * Build the administration menu as renderable menu links.
  *
  * @param $tree
@@ -22,8 +343,8 @@
 function admin_menu_links_menu($tree) {
   $links = array();
   foreach ($tree as $data) {
-    // Skip menu callbacks (mostly dynamic items).
-    if (isset($data['link']['type']) && $data['link']['type'] == MENU_CALLBACK) {
+    // Skip invisible items.
+    if (!$data['link']['access'] || $data['link']['type'] == MENU_CALLBACK) {
       continue;
     }
     // Hide 'Administer' and make child links appear on this level.
diff --git admin_menu.install admin_menu.install
index 69c4d68..c0309ae 100644
--- admin_menu.install
+++ admin_menu.install
@@ -88,3 +88,16 @@ function admin_menu_update_7302() {
     ->execute();
 }
 
+/**
+ * Remove local tasks from {menu_links} table.
+ */
+function admin_menu_update_7303() {
+  $paths = db_query('SELECT path FROM {menu_router} WHERE path LIKE :prefix AND type & :type', array(
+    ':prefix' => 'admin/%',
+    ':type' => MENU_IS_LOCAL_TASK,
+  ))->fetchCol();
+  db_delete('menu_links')
+    ->condition('router_path', $paths, 'IN')
+    ->execute();
+}
+
diff --git admin_menu.map.inc admin_menu.map.inc
new file mode 100644
index 0000000..07f2051
--- /dev/null
+++ admin_menu.map.inc
@@ -0,0 +1,123 @@
+<?php
+// $Id: admin_menu.inc,v 1.68 2009/11/04 21:51:19 sun Exp $
+
+/**
+ * @file
+ * Implements hook_admin_menu_map() on behalf of other modules.
+ *
+ * @todo Replace all/most of those API functions with direct DB queries;
+ *   we only need the menu arguments (keys), not fully loaded objects.
+ */
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Filter module.
+ */
+function filter_admin_menu_map() {
+  $map['admin/config/content/formats/%filter_format'] = array(
+    'parent' => 'admin/config/content/formats',
+    'hide' => 'admin/config/content/formats/list',
+    'arguments' => array(
+      array('%filter_format' => array_keys(filter_formats())),
+    ),
+  );
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Menu module.
+ */
+function menu_admin_menu_map() {
+  $map['admin/structure/menu/manage/%menu'] = array(
+    'parent' => 'admin/structure/menu',
+    'hide' => 'admin/structure/menu/list',
+    'arguments' => array(
+      array('%menu' => array_keys(menu_get_menus())),
+    ),
+  );
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Node module.
+ */
+function node_admin_menu_map() {
+  $map['admin/structure/types/manage/%node_type'] = array(
+    'parent' => 'admin/structure/types',
+    'hide' => 'admin/structure/types/list',
+    'arguments' => array(
+      array('%node_type' => array_keys(node_type_get_types())),
+    ),
+  );
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Field UI module.
+ */
+function field_ui_admin_menu_map() {
+  foreach (entity_get_info() as $obj_type => $info) {
+    foreach ($info['bundles'] as $bundle_name => $bundle_info) {
+      if (isset($bundle_info['admin'])) {
+        $arguments = array();
+        switch ($obj_type) {
+          case 'node':
+            // Provide replacement sets for content types, note that the
+            // fields (%field_ui_menu) are different for each content type.
+            foreach (array_keys($info['bundles']) as $node_type) {
+              $fields = array();
+              foreach (field_info_instances($obj_type, $node_type) as $field) {
+                $fields[] = $field['field_name'];
+              }
+              $arguments[] = array(
+                '%node_type' => array($node_type),
+                '%field_ui_menu' => $fields,
+              );
+            }
+            break;
+
+          case 'user':
+            $arguments = array(array('%field_ui_menu' => array_keys(field_info_fields('user'))));
+            break;
+        }
+        if (!empty($arguments)) {
+          $path = $bundle_info['admin']['path'];
+          $map["$path/fields/%field_ui_menu"] = array(
+            'parent' => "$path/fields",
+            'arguments' => $arguments,
+          );
+        }
+      }
+    }
+  }
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Taxonomy module.
+ */
+function taxonomy_admin_menu_map() {
+  $map['admin/structure/taxonomy/%taxonomy_vocabulary'] = array(
+    'parent' => 'admin/structure/taxonomy',
+    'hide' => 'admin/structure/taxonomy/list',
+    'arguments' => array(
+      array('%taxonomy_vocabulary' => array_keys(taxonomy_get_vocabularies())),
+    ),
+  );
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Views UI module.
+ */
+function views_ui_admin_menu_map() {
+  // @todo Requires patch to views_ui.
+  $map['admin/structure/views/edit/%views_ui_cache'] = array(
+    'parent' => 'admin/structure/views',
+    'hide' => 'admin/structure/views/list',
+    'arguments' => array(
+      array('%views_ui_cache' => array_keys(views_get_all_views())),
+    ),
+  );
+  return $map;
+}
+
diff --git admin_menu.module admin_menu.module
index b093f50..1fee7f0 100644
--- admin_menu.module
+++ admin_menu.module
@@ -406,7 +406,7 @@ function admin_menu_output() {
     module_load_include('inc', 'admin_menu');
 
     // Add administration menu.
-    $content['menu'] = admin_menu_links_menu(menu_tree_all_data('management'));
+    $content['menu'] = admin_menu_links_menu(admin_menu_tree('management'));
     $content['menu']['#theme'] = 'admin_menu_links';
     // Ensure the menu tree is rendered between the icon and user links.
     $content['menu']['#weight'] = 0;
