Index: wp-admin/menu-header.php
===================================================================
--- wp-admin/menu-header.php	(revision 15560)
+++ wp-admin/menu-header.php	(working copy)
@@ -47,7 +47,7 @@
 		if ( !empty($submenu[$item[2]]) )
 			$class[] = 'wp-has-submenu';
 
-		if ( ( $parent_file && $item[2] == $parent_file ) || ( false === strpos($parent_file, '?') && $self == $item[2] ) ) {
+		if ( ( $parent_file && $item[2] == $parent_file ) || ( empty($typenow) && $self == $item[2] ) ) {
 			if ( !empty($submenu[$item[2]]) )
 				$class[] = 'wp-has-current-submenu wp-menu-open';
 			else
Index: wp-admin/menu.php
===================================================================
--- wp-admin/menu.php	(revision 15560)
+++ wp-admin/menu.php	(working copy)
@@ -105,8 +105,11 @@
 
 $_wp_last_object_menu = 25; // The index of the last top-level menu in the object menu group
 
-foreach ( (array) get_post_types( array('show_ui' => true, '_builtin' => false) ) as $ptype ) {
+foreach ( (array) get_post_types( array('show_ui' => true, '_builtin' => false, 'show_in_menu' => true ) ) as $ptype ) {
 	$ptype_obj = get_post_type_object( $ptype );
+	// Check if it should be a submenu.
+	if ( $ptype_obj->show_in_menu !== true )
+		continue;
 	$ptype_menu_position = is_int( $ptype_obj->menu_position ) ? $ptype_obj->menu_position : ++$_wp_last_object_menu; // If we're to use $_wp_last_object_menu, increment it first.
 	$ptype_for_id = sanitize_html_class( $ptype );
 	if ( is_string( $ptype_obj->menu_icon ) ) {
Index: wp-includes/post.php
===================================================================
--- wp-includes/post.php	(revision 15560)
+++ wp-includes/post.php	(working copy)
@@ -778,6 +778,7 @@
  * - exclude_from_search - Whether to exclude posts with this post type from search results. Defaults to true if the type is not public, false if the type is public.
  * - publicly_queryable - Whether post_type queries can be performed from the front page.  Defaults to whatever public is set as.
  * - show_ui - Whether to generate a default UI for managing this post type. Defaults to true if the type is public, false if the type is not public.
+ * - show_in_menu - Where to show the post type in the admin menu. True for a top level menu, false for no menu, or can be a top level page like 'tools.php' or 'edit.php?post_type=page'. show_ui must be true.
  * - menu_position - The position in the menu order the post type should appear. Defaults to the bottom.
  * - menu_icon - The url to the icon to be used for this menu. Defaults to use the posts icon.
  * - capability_type - The post type to use for checking read, edit, and delete capabilities. Defaults to "post".
@@ -814,7 +815,7 @@
 		'_builtin' => false, '_edit_link' => 'post.php?post=%d', 'capability_type' => 'post', 'capabilities' => array(), 'hierarchical' => false,
 		'public' => false, 'rewrite' => true, 'query_var' => true, 'supports' => array(), 'register_meta_box_cb' => null,
 		'taxonomies' => array(), 'show_ui' => null, 'menu_position' => null, 'menu_icon' => null,
-		'permalink_epmask' => EP_PERMALINK, 'can_export' => true, 'show_in_nav_menus' => null
+		'permalink_epmask' => EP_PERMALINK, 'can_export' => true, 'show_in_nav_menus' => null, 'show_in_menu' => null,
 	);
 	$args = wp_parse_args($args, $defaults);
 	$args = (object) $args;
@@ -830,6 +831,10 @@
 	if ( null === $args->show_ui )
 		$args->show_ui = $args->public;
 
+	// If not set, default to the setting for show_ui.
+	if ( null === $args->show_in_menu )
+		$args->show_in_menu = $args->show_ui;
+
 	// Whether to show this type in nav-menus.php.  Defaults to the setting for public.
 	if ( null === $args->show_in_nav_menus )
 		$args->show_in_nav_menus = $args->public;
@@ -963,6 +968,7 @@
  * Builds an object with custom-something object (post type, taxonomy) labels out of a custom-something object
  *
  * @access private
+ * @since 3.0.0
  */
 function _get_custom_object_labels( $object, $nohier_vs_hier_defaults ) {
 
@@ -978,6 +984,23 @@
 }
 
 /**
+ * Adds submenus for post types.
+ *
+ * @access private
+ * @since 3.1.0
+ */ 
+function _add_post_type_submenus() {
+	foreach ( get_post_types( array( 'show_ui' => true ) ) as $ptype ) {
+		$ptype_obj = get_post_type_object( $ptype );
+		// Submenus only.
+		if ( ! $ptype_obj->show_in_menu || $ptype_obj->show_in_menu === true )
+			continue;
+		add_submenu_page( $ptype_obj->show_in_menu, $ptype_obj->labels->name, $ptype_obj->labels->name, $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype" );
+	}
+}
+add_action( 'admin_menu', '_add_post_type_submenus' );
+
+/**
  * Register support of certain features for a post type.
  *
  * All features are directly associated with a functional area of the edit screen, such as the
