Index: wp-includes/post-template.php
===================================================================
--- wp-includes/post-template.php	(revision 15812)
+++ wp-includes/post-template.php	(working copy)
@@ -407,7 +407,10 @@
 			$classes[] = 'attachment-' . str_replace( $mime_prefix, '', $mime_type );
 		}
 	} elseif ( is_archive() ) {
-		if ( is_author() ) {
+		if ( is_post_type_archive() ) {
+			$classes[] = 'post-type-archive';
+			$classes[] = 'post-type-archive-' . sanitize_html_class( get_query_var( 'post_type' ) );
+		} else if ( is_author() ) {
 			$author = $wp_query->get_queried_object();
 			$classes[] = 'author';
 			$classes[] = 'author-' . sanitize_html_class( $author->user_nicename , $author->ID );
@@ -472,6 +475,8 @@
 			$classes[] = 'author-paged-' . $page;
 		elseif ( is_search() )
 			$classes[] = 'search-paged-' . $page;
+		elseif ( is_post_type_archive() )
+			$classes[] = 'post-type-paged-' . $page;
 	}
 
 	if ( !empty( $class ) ) {
Index: wp-includes/post.php
===================================================================
--- wp-includes/post.php	(revision 15812)
+++ wp-includes/post.php	(working copy)
@@ -924,7 +924,7 @@
 		if ( !isset($args->rewrite['archive']) )
 			$args->rewrite['archive'] = false;
 		if ( !isset($args->rewrite['feeds']) || !$args->rewrite['archive'] )
-			$args->rewrite['feeds'] = false;
+			$args->rewrite['feeds'] = (bool) $args->rewrite['archive'];
 
 		if ( $args->hierarchical )
 			$wp_rewrite->add_rewrite_tag("%$post_type%", '(.+?)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name=");
Index: wp-includes/query.php
===================================================================
--- wp-includes/query.php	(revision 15812)
+++ wp-includes/query.php	(working copy)
@@ -121,6 +121,22 @@
 }
 
 /**
+ * Is the query for a post type archive page?
+ *
+ * @see WP_Query::is_post_type_archive()
+ * @since 3.1.0
+ * @uses $wp_query
+ *
+ * @param mixed $post_types Optional. Post type or array of posts types to check against.
+ * @return bool
+ */
+function is_post_type_archive( $post_types = '' ) {
+	global $wp_query;
+
+	return $wp_query->is_post_type_archive( $post_types );
+}
+	
+/**
  * Is the query for an attachment page?
  *
  * @see WP_Query::is_attachment()
@@ -1041,6 +1057,15 @@
 	var $is_posts_page = false;
 
 	/**
+	 * Set if query is for a post type archive.
+	 *
+	 * @since 3.1.0
+	 * @access public
+	 * @var bool
+	 */
+	var $is_post_type_archive = false;
+
+	/**
 	 * Resets query flags to false.
 	 *
 	 * The query flags are what page info WordPress was able to figure out.
@@ -1075,6 +1100,7 @@
 		$this->is_singular = false;
 		$this->is_robots = false;
 		$this->is_posts_page = false;
+		$this->is_post_type_archive = false;
 	}
 
 	/**
@@ -1234,7 +1260,7 @@
 			$this->is_page = true;
 			$this->is_single = false;
 		} else {
-		// Look for archive queries.  Dates, categories, authors, search.
+		// Look for archive queries.  Dates, categories, authors, search, post type archives.
 
 			if ( !empty($qv['s']) ) {
 				$this->is_search = true;
@@ -1306,10 +1332,13 @@
 			if ( '' != $qv['author_name'] )
 				$this->is_author = true;
 
-			if ( !empty( $qv['post_type'] ) )
-				$this->is_archive = true;
+			if ( !empty( $qv['post_type'] ) && ! is_array( $qv['post_type'] ) ) {
+				$post_type_obj = get_post_type_object( $qv['post_type'] );
+				if ( is_array( $post_type_obj->rewrite ) && $post_type_obj->rewrite['archive'] )
+					$this->is_post_type_archive = true;
+			}
 
-			if ( $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax )
+			if ( $this->is_post_type_archive || $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax )
 				$this->is_archive = true;
 		}
 
@@ -2636,6 +2665,26 @@
 	}
 
 	/**
+	 * Is the query for a post type archive page?
+	 *
+	 * @since 3.1.0
+	 *
+	 * @param mixed $post_types Optional. Post type or array of posts types to check against.
+	 * @return bool
+	 */
+	function is_post_type_archive( $post_types = '' ) {
+		if ( empty( $post_types ) || !$this->is_post_type_archive )
+			return (bool) $this->is_post_type_archive;
+
+		if ( ! isset( $this->posts[0] ) )
+			return false;
+
+		$post = $this->posts[0];
+
+		return in_array( $post->post_type, (array) $post_types );
+	}
+
+	/**
 	 * Is the query for an attachment page?
 	 *
 	 * @since 3.1.0
Index: wp-includes/link-template.php
===================================================================
--- wp-includes/link-template.php	(revision 15812)
+++ wp-includes/link-template.php	(working copy)
@@ -39,7 +39,7 @@
 		$string = untrailingslashit($string);
 
 	// Note that $type_of_url can be one of following:
-	// single, single_trackback, single_feed, single_paged, feed, category, page, year, month, day, paged
+	// single, single_trackback, single_feed, single_paged, feed, category, page, year, month, day, paged, post_type_archive
 	$string = apply_filters('user_trailingslashit', $string, $type_of_url);
 	return $string;
 }
@@ -825,6 +825,63 @@
 }
 
 /**
+ * Retrieve the permalink for a post type archive.
+ *
+ * @since 3.1.0
+ *
+ * @param string $post_type Post type
+ * @return string
+ */
+function get_post_type_archive_link( $post_type ) {
+	global $wp_rewrite;
+	if ( ! $post_type_obj = get_post_type_object( $post_type ) )
+		return false;
+
+	if ( ! is_array( $post_type_obj->rewrite ) || false === $post_type_obj->rewrite['archive'] )
+		return false;
+
+	if ( get_option( 'permalink_structure' ) ) {
+		$struct = ( true === $post_type_obj->rewrite['archive'] ) ? $post_type_obj->rewrite['slug'] : $post_type_obj->rewrite['archive'];
+		if ( $post_type_obj->rewrite['with_front'] )
+			$struct = $wp_rewrite->front . $struct;
+		$link = home_url( user_trailingslashit( $struct, 'post_type_archive' ) );
+	} else {
+		$link = home_url( '?post_type=' . $post_type );
+	}
+
+	return apply_filters( 'post_type_archive_link', $link, $post_type );
+}
+
+/**
+ * Retrieve the permalink for a post type archive feed.
+ *
+ * @since 3.1.0
+ *
+ * @param string $post_type Post type
+ * @param string $feed Optional. Feed type 
+ * @return string
+ */	
+function get_post_type_archive_feed_link( $post_type, $feed = '' ) {
+	$default_feed = get_default_feed();
+	if ( empty( $feed ) )
+		$feed = $default_feed;
+
+	if ( ! $link = get_post_type_archive_link( $post_type ) )
+		return false;
+	$post_type_obj = get_post_type_object( $post_type );
+	if ( $post_type_obj->rewrite['feeds'] && get_option( 'permalink_structure' ) ) {
+		$link = trailingslashit($link);
+		$link .= 'feed/';
+		if ( $feed != $default_feed )
+			$link .= "$feed/";
+	} else {
+		$link = add_query_arg( 'feed', $feed, $link );
+	}
+
+	return apply_filters( 'post_type_archive_feed_link', $link, $feed );
+}
+
+/**
  * Retrieve edit posts link for post.
  *
  * Can be used within the WordPress loop or outside of it. Can be used with
Index: wp-includes/general-template.php
===================================================================
--- wp-includes/general-template.php	(revision 15812)
+++ wp-includes/general-template.php	(working copy)
@@ -547,6 +547,10 @@
 		$title = $author->display_name;
 	}
 
+	// If there's a post type archive
+	if ( is_post_type_archive() )
+		$title = post_type_archive_title( '', false );
+
 	// If there's a month
 	if ( is_archive() && !empty($m) ) {
 		$my_year = substr($m, 0, 4);
@@ -611,7 +615,6 @@
  * be a space, the parameter value will need to have it at the end.
  *
  * @since 0.71
- * @uses $wpdb
  *
  * @param string $prefix Optional. What to display before the title.
  * @param bool $display Optional, default is true. Whether to display or retrieve title.
@@ -636,6 +639,32 @@
 }
 
 /**
+ * Display or retrieve title for a post type archive.
+ *
+ * This is optimized for archive.php and archive-{$post_type}.php template files
+ * for displaying the title of the post type.
+ *
+ * @since 3.1.0
+ *
+ * @param string $prefix Optional. What to display before the title.
+ * @param bool $display Optional, default is true. Whether to display or retrieve title.
+ * @return string|null Title when retrieving, null when displaying or failure.
+ */
+function post_type_archive_title() {
+	if ( ! is_post_type_archive() )
+		return;
+
+	
+	$post_type_obj = get_post_type_object( get_query_var( 'post_type' ) );
+	$title = apply_filters('post_type_archive_title', $post_type_obj->labels->name );
+
+	if ( $display )
+		echo $prefix . $title;
+	else
+		return $title;
+}
+	
+/**
  * Display or retrieve page title for category archive.
  *
  * This is useful for category template file or files, because it is optimized

