Index: wp-admin/includes/meta-boxes.php
===================================================================
--- wp-admin/includes/meta-boxes.php	(revision 18519)
+++ wp-admin/includes/meta-boxes.php	(working copy)
@@ -569,13 +569,14 @@
 <?php
 		} // end empty pages check
 	} // end hierarchical check.
-	if ( 'page' == $post->post_type && 0 != count( get_page_templates() ) ) {
+	if ( 0 != count( get_post_type_templates( $post->post_type ) ) ) {
 		$template = !empty($post->page_template) ? $post->page_template : false;
 		?>
 <p><strong><?php _e('Template') ?></strong></p>
-<label class="screen-reader-text" for="page_template"><?php _e('Page Template') ?></label><select name="page_template" id="page_template">
-<option value='default'><?php _e('Default Template'); ?></option>
-<?php page_template_dropdown($template); ?>
+<label class="screen-reader-text" for="page_template"><?php _e('Template') ?></label>
+<select name="page_template" id="page_template">
+	<option value='default'><?php _e('Default Template'); ?></option>
+	<?php post_type_template_dropdown( $template, $post->post_type ); ?>
 </select>
 <?php
 	} ?>
Index: wp-admin/includes/post.php
===================================================================
--- wp-admin/includes/post.php	(revision 18519)
+++ wp-admin/includes/post.php	(working copy)
@@ -476,8 +476,7 @@
 
 	$post = get_post( $id, OBJECT, 'edit' );
 
-	if ( $post->post_type == 'page' )
-		$post->page_template = get_post_meta( $id, '_wp_page_template', true );
+	$post->page_template = get_post_meta( $id, '_wp_page_template', true );
 
 	return $post;
 }
Index: wp-admin/includes/template.php
===================================================================
--- wp-admin/includes/template.php	(revision 18519)
+++ wp-admin/includes/template.php	(working copy)
@@ -291,8 +291,7 @@
 	if ( $post_type_object->hierarchical )
 		echo '<div class="post_parent">' . $post->post_parent . '</div>';
 
-	if ( $post->post_type == 'page' )
-		echo '<div class="page_template">' . esc_html( get_post_meta( $post->ID, '_wp_page_template', true ) ) . '</div>';
+	echo '<div class="page_template">' . esc_html( get_post_meta( $post->ID, '_wp_page_template', true ) ) . '</div>';
 
 	if ( $post_type_object->hierarchical )
 		echo '<div class="menu_order">' . $post->menu_order . '</div>';
@@ -647,25 +646,37 @@
 }
 
 /**
- * {@internal Missing Short Description}}
+ * Display dropdown options for template files from the active theme
  *
- * @since 1.5.0
+ * @since 3.3
  *
- * @param unknown_type $default
+ * @param string $default Template file to select by default
+ * @param string $post_type Post type
  */
-function page_template_dropdown( $default = '' ) {
-	$templates = get_page_templates();
+function post_type_template_dropdown( $default = '', $post_type = 'page' ) {
+	$templates = get_post_type_templates( $post_type );
 	ksort( $templates );
-	foreach (array_keys( $templates ) as $template )
-		: if ( $default == $templates[$template] )
+	foreach ( array_keys( $templates ) as $template ) {
+		if ( $default == $templates[$template] )
 			$selected = " selected='selected'";
 		else
 			$selected = '';
-	echo "\n\t<option value='".$templates[$template]."' $selected>$template</option>";
-	endforeach;
+		echo "\n\t<option value='" . $templates[$template] . "' $selected>$template</option>";
+	}
 }
 
 /**
+ * Display dropdown options for page template files from the active theme
+ *
+ * @since 1.5.0
+ *
+ * @param string $default Template to select by default
+ */
+function page_template_dropdown( $default = '' ) {
+	post_type_template_dropdown( $default, 'page' );
+}
+
+/**
  * {@internal Missing Short Description}}
  *
  * @since 1.5.0
Index: wp-admin/includes/theme.php
===================================================================
--- wp-admin/includes/theme.php	(revision 18519)
+++ wp-admin/includes/theme.php	(working copy)
@@ -159,47 +159,80 @@
 }
 
 /**
- * Get the Page Templates available in this theme
+ * Get the templates available in this theme for the given post type
  *
- * @since 1.5.0
+ * @since 3.3
  *
  * @return array Key is the template name, value is the filename of the template
  */
-function get_page_templates() {
+function get_post_type_templates( $post_type ) {
+	static $post_type_templates;
+
+	if ( isset( $post_type_templates ) ) {
+		if ( isset( $post_type_templates[$post_type] ) )
+			return $post_type_templates[$post_type];
+		else
+			return array();
+	}
+
 	$themes = get_themes();
 	$theme = get_current_theme();
 	$templates = $themes[$theme]['Template Files'];
-	$page_templates = array();
+	$post_type_templates = array();
 
 	if ( is_array( $templates ) ) {
-		$base = array( trailingslashit(get_template_directory()), trailingslashit(get_stylesheet_directory()) );
+		$base = array( trailingslashit( get_template_directory() ), trailingslashit( get_stylesheet_directory() ) );
 
 		foreach ( $templates as $template ) {
-			$basename = str_replace($base, '', $template);
+			$basename = str_replace( $base, '', $template );
 
 			// don't allow template files in subdirectories
-			if ( false !== strpos($basename, '/') )
+			if ( false !== strpos( $basename, '/' ) )
 				continue;
 
 			if ( 'functions.php' == $basename )
 				continue;
 
-			$template_data = implode( '', file( $template ));
+			$template_data = implode( '', file( $template ) );
+			$name = '';
 
-			$name = '';
 			if ( preg_match( '|Template Name:(.*)$|mi', $template_data, $name ) )
-				$name = _cleanup_header_comment($name[1]);
+				$name = trim( _cleanup_header_comment( $name[1] ) );
 
+			if ( preg_match( '|Template Type:(.*)$|mi', $template_data, $type ) )
+				$types = explode( ',', _cleanup_header_comment( $type[1] ) );
+			else
+				$types = array( 'page' );
+
 			if ( !empty( $name ) ) {
-				$page_templates[trim( $name )] = $basename;
+				foreach ( $types as $type ) {
+					$type = trim( $type );
+					if ( !isset( $post_type_templates[$type] ) )
+						$post_type_templates[$type] = array();
+					$post_type_templates[$type][$name] = $basename;
+				}
 			}
 		}
 	}
 
-	return $page_templates;
+	if ( isset( $post_type_templates[$post_type] ) )
+		return $post_type_templates[$post_type];
+	else
+		return array();
 }
 
 /**
+ * Get the Page Templates available in this theme
+ *
+ * @since 1.5.0
+ *
+ * @return array Key is the template name, value is the filename of the template
+ */
+function get_page_templates() {
+	return get_post_type_templates( 'page' );
+}
+
+/**
  * Tidies a filename for url display by the theme editor.
  *
  * @since 2.9.0
Index: wp-includes/post-template.php
===================================================================
--- wp-includes/post-template.php	(revision 18519)
+++ wp-includes/post-template.php	(working copy)
@@ -1235,14 +1235,11 @@
  * @return bool False on failure, true if success.
  */
 function is_page_template($template = '') {
-	if (!is_page()) {
-		return false;
-	}
 
 	global $wp_query;
 
-	$page = $wp_query->get_queried_object();
-	$custom_fields = get_post_custom_values('_wp_page_template',$page->ID);
+	$post = $wp_query->get_queried_object();
+	$custom_fields = get_post_custom_values('_wp_page_template',$post->ID);
 	$page_template = $custom_fields[0];
 
 	// We have no argument passed so just see if a page_template has been specified
Index: wp-includes/post.php
===================================================================
--- wp-includes/post.php	(revision 18519)
+++ wp-includes/post.php	(working copy)
@@ -2621,9 +2621,9 @@
 
 	$post = get_post($post_ID);
 
-	if ( !empty($page_template) && 'page' == $data['post_type'] ) {
+	if ( !empty($page_template) ) {
 		$post->page_template = $page_template;
-		$page_templates = get_page_templates();
+		$page_templates = get_post_type_templates( $post->post_type );
 		if ( 'default' != $page_template && !in_array($page_template, $page_templates) ) {
 			if ( $wp_error )
 				return new WP_Error('invalid_page_template', __('The page template is invalid.'));
Index: wp-includes/theme.php
===================================================================
--- wp-includes/theme.php	(revision 18519)
+++ wp-includes/theme.php	(working copy)
@@ -1001,8 +1001,14 @@
  */
 function get_single_template() {
 	$object = get_queried_object();
+	$template = get_post_meta( $object->ID, '_wp_page_template', true );
 
+	if ( 'default' == $template )
+		$template = '';
+
 	$templates = array();
+	if ( !empty($template) && !validate_file($template) )
+		$templates[] = $template;
 
 	$templates[] = "single-{$object->post_type}.php";
 	$templates[] = "single.php";
