Index: wp-includes/post.php
===================================================================
--- wp-includes/post.php	(revision 21356)
+++ wp-includes/post.php	(working copy)
@@ -977,7 +977,7 @@
 	$defaults = array(
 		'labels' => array(), 'description' => '', 'publicly_queryable' => null, 'exclude_from_search' => null,
 		'capability_type' => 'post', 'capabilities' => array(), 'map_meta_cap' => null,
-		'_builtin' => false, '_edit_link' => 'post.php?post=%d', 'hierarchical' => false,
+		'_builtin' => false, '_edit_link' => 'post.php?post=%d', 'hierarchical' => false, 'show_taxonomy_columns' => false,
 		'public' => false, 'rewrite' => true, 'has_archive' => false, 'query_var' => true,
 		'supports' => array(), 'register_meta_box_cb' => null,
 		'taxonomies' => array(), 'show_ui' => null, 'menu_position' => null, 'menu_icon' => null,
Index: wp-admin/includes/screen.php
===================================================================
--- wp-admin/includes/screen.php	(revision 21356)
+++ wp-admin/includes/screen.php	(working copy)
@@ -23,10 +23,45 @@
 	if ( ! isset( $column_headers[ $screen->id ] ) )
 		$column_headers[ $screen->id ] = apply_filters( 'manage_' . $screen->id . '_columns', array() );

-	return $column_headers[ $screen->id ];
+	$tax_columns = ( $screen->post_type ) ? get_taxonomy_column_headers( $screen ) : array();
+
+	return array_merge( $column_headers[ $screen->id ], $tax_columns );
 }

 /**
+ * Get a list of registered taxonomy column headers.
+ *
+ * @since 3.5.0
+ *
+ * @param object|WP_Screen $screen The screen you want the headers for
+ * @return array Containing the headers in the format id => UI String
+ */
+function get_taxonomy_column_headers( $screen ) {
+	$columns = array();
+
+	$post_type_object = get_post_type_object( $screen->post_type );
+
+	if ( $post_type_object->show_taxonomy_columns ) {
+
+		if ( is_array( $post_type_object->show_taxonomy_columns ) )
+			$taxonomies = $post_type_object->show_taxonomy_columns;
+		else
+			$taxonomies = get_object_taxonomies( $screen->post_type );
+
+		if ( empty( $taxonomies ) )
+			return $columns;
+
+		foreach ( $taxonomies as $registered_taxonomy ) {
+
+			$taxonomy_object = get_taxonomy( $registered_taxonomy );
+			$columns[$registered_taxonomy.'_taxonomy_column'] = apply_filters( 'taxonomy_column_header', $taxonomy_object->label, $post_type_object, $taxonomy_object );
+
+		}
+	}
+	return $columns;
+}
+
+/**
  * Get a list of hidden columns.
  *
  * @since 2.7.0
Index: wp-admin/includes/class-wp-posts-list-table.php
===================================================================
--- wp-admin/includes/class-wp-posts-list-table.php	(revision 21356)
+++ wp-admin/includes/class-wp-posts-list-table.php	(working copy)
@@ -469,6 +469,12 @@
 		$edit_link = get_edit_post_link( $post->ID );
 		$title = _draft_or_post_title();
 		$post_type_object = get_post_type_object( $post->post_type );
+		if ( $post_type_object->show_taxonomy_columns ) {
+			if ( is_array( $post_type_object->show_taxonomy_columns ) )
+					$taxonomies_columns = $post_type_object->show_taxonomy_columns;
+			else
+				$taxonomies_columns = get_object_taxonomies( $post_type_object->name );
+		}
 		$can_edit_post = current_user_can( $post_type_object->cap->edit_post, $post->ID );

 		$alternate = 'alternate' == $alternate ? '' : 'alternate';
@@ -529,7 +535,7 @@
 				}
 				else {
 					$attributes = 'class="post-title page-title column-title"' . $style;
-
+
 					$pad = str_repeat( '&#8212; ', $level );
 ?>
 			<td <?php echo $attributes ?>><strong><?php if ( $can_edit_post && $post->post_status != 'trash' ) { ?><a class="row-title" href="<?php echo $edit_link; ?>" title="<?php echo esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $title ) ); ?>"><?php echo $pad; echo $title ?></a><?php } else { echo $pad; echo $title; }; _post_states( $post ); ?></strong>
@@ -604,47 +610,24 @@
 			break;

 			case 'categories':
-			?>
-			<td <?php echo $attributes ?>><?php
-				$categories = get_the_category();
-				if ( !empty( $categories ) ) {
-					$out = array();
-					foreach ( $categories as $c ) {
-						$out[] = sprintf( '<a href="%s">%s</a>',
-							esc_url( add_query_arg( array( 'post_type' => $post->post_type, 'category_name' => $c->slug ), 'edit.php' ) ),
-							esc_html( sanitize_term_field( 'name', $c->name, $c->term_id, 'category', 'display' ) )
-						);
-					}
-					/* translators: used between list items, there is a space after the comma */
-					echo join( __( ', ' ), $out );
-				} else {
-					_e( 'Uncategorized' );
-				}
-			?></td>
-			<?php
+			$this->taxonomy_column( array( 'attributes' => $attributes, 'empty' => __( 'Uncategorized' )	) );
 			break;

 			case 'tags':
-			?>
-			<td <?php echo $attributes ?>><?php
-				$tags = get_the_tags( $post->ID );
-				if ( !empty( $tags ) ) {
-					$out = array();
-					foreach ( $tags as $c ) {
-						$out[] = sprintf( '<a href="%s">%s</a>',
-							esc_url( add_query_arg( array( 'post_type' => $post->post_type, 'tag' => $c->slug ), 'edit.php' ) ),
-							esc_html( sanitize_term_field( 'name', $c->name, $c->term_id, 'tag', 'display' ) )
-						);
-					}
-					/* translators: used between list items, there is a space after the comma */
-					echo join( __( ', ' ), $out );
-				} else {
-					_e( 'No Tags' );
-				}
-			?></td>
-			<?php
+			$this->taxonomy_column( array( 'taxonomy' => 'post_tag', 'attributes' => $attributes	) );
 			break;

+			case ( is_array( $taxonomies_columns ) && in_array( $registered_taxonomy = str_replace( '_taxonomy_column', '', $column_name ), $taxonomies_columns ) ) :
+
+			$defaults = array(
+				'taxonomy' => $registered_taxonomy,
+				'attributes' => $attributes,
+			);
+			$args = apply_filters( 'taxonomy_column_args', $defaults, $post_type_object, $registered_taxonomy  );
+
+			$this->taxonomy_column( $args );
+			break;
+
 			case 'comments':
 			?>
 			<td <?php echo $attributes ?>><div class="post-com-count-wrapper">
@@ -679,8 +662,8 @@
 			?></td>
 			<?php
 			break;
+			}
 		}
-	}
 	?>
 		</tr>
 	<?php
@@ -688,6 +671,46 @@
 	}

 	/**
+	 * Creates internal taxonomy columns as well as registered taxonomies
+	 *
+	 * @since 3.5.0
+	 */
+	function taxonomy_column( $atts = array() ) {
+		global $post;
+
+		$defaults = array(
+			'taxonomy' => 'category',
+			'attributes' => '',
+			'empty' => '',
+		);
+		$args = wp_parse_args( (array) $atts, $defaults );
+		extract( $args, EXTR_SKIP );
+
+		$attributes = !empty( $attributes ) ? $attributes : 'class="column-'. $taxonomy .'"';
+		$taxonomy_object = get_taxonomy( $taxonomy );
+		$empty = !empty( $empty ) ? $empty : __( 'No '. $taxonomy_object->label );
+
+		?>
+		<td <?php echo $attributes ?>><?php
+			$terms = get_the_terms( $post->ID, $taxonomy );
+			if ( !empty( $terms ) ) {
+				$out = array();
+				foreach ( $terms as $t ) {
+					$out[] = sprintf( '<a href="%s">%s</a>',
+						esc_url( add_query_arg( array( 'post_type' => $post->post_type, $taxonomy_object->query_var => $t->slug ), 'edit.php' ) ),
+						esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) )
+					);
+				}
+				/* translators: used between list items, there is a space after the comma */
+				echo join( __( ', ' ), $out );
+			} else {
+				echo $empty;
+			}
+		?></td>
+		<?php
+	}
+
+	/**
 	 * Outputs the hidden row displayed when inline editing
 	 *
 	 * @since 3.1.0
