diff --git src/wp-includes/class-wp-query.php src/wp-includes/class-wp-query.php
index eb68f21..3b56ee5 100644
--- src/wp-includes/class-wp-query.php
+++ src/wp-includes/class-wp-query.php
@@ -346,6 +346,24 @@ class WP_Query {
 	public $is_comment_feed = false;
 
 	/**
+	 * Set if query is home feed display.
+	 *
+	 * @since 4.7.1
+	 * @access public
+	 * @var bool
+	 */
+	public $is_home_feed = false;
+
+	/**
+	 * Set if query is custom feed display.
+	 *
+	 * @since 4.7.1
+	 * @access public
+	 * @var bool
+	 */
+	public $is_custom_feed = false;
+
+	/**
 	 * Set if query is trackback.
 	 *
 	 * @since 1.5.0
@@ -511,6 +529,8 @@ class WP_Query {
 		$this->is_search = false;
 		$this->is_feed = false;
 		$this->is_comment_feed = false;
+		$this->is_home_feed = false;
+		$this->is_custom_feed = false;
 		$this->is_trackback = false;
 		$this->is_home = false;
 		$this->is_404 = false;
@@ -927,8 +947,12 @@ class WP_Query {
 				$this->is_archive = true;
 		}
 
-		if ( '' != $qv['feed'] )
+		if ( '' != $qv['feed'] ) {
 			$this->is_feed = true;
+			if ( ! in_array( $qv['feed'], array( 'feed', 'rss', 'rss2', 'atom', 'rdf' ) ) ) {
+				$this->is_custom_feed = true;
+			}
+		}
 
 		if ( '' != $qv['embed'] ) {
 			$this->is_embed = true;
@@ -957,8 +981,18 @@ class WP_Query {
 		if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) )
 			$this->is_comment_feed = true;
 
-		if ( !( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots ) )
-			$this->is_home = true;
+
+
+		if ( !( $this->is_singular || $this->is_archive || $this->is_search || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots || $this->is_custom_feed ) ) {
+			if ( $this->is_feed ) {
+				if ( ! $this->is_comment_feed ) {
+					$this->is_home_feed = true;
+				}
+			} else {
+				$this->is_home = true;
+			}
+
+		}
 
 		// Correct is_* for page_on_front and page_for_posts
 		if ( $this->is_home && 'page' == get_option('show_on_front') && get_option('page_on_front') ) {
@@ -3668,6 +3702,28 @@ class WP_Query {
 	}
 
 	/**
+	 * Is the query for a hompage feed?
+	 *
+	 * @since 4.7.1
+	 *
+	 * @return bool
+	 */
+	public function is_home_feed() {
+		return (bool) $this->is_home_feed;
+	}
+
+	/**
+	 * Is the query for a custom feed?
+	 *
+	 * @since 4.7.1
+	 *
+	 * @return bool
+	 */
+	public function is_custom_feed() {
+		return (bool) $this->is_custom_feed;
+	}
+
+	/**
 	 * Is the query for the front page of the site?
 	 *
 	 * This is for what is displayed at your site's main URL.
diff --git src/wp-includes/functions.php src/wp-includes/functions.php
index 914cbb9..733a718 100644
--- src/wp-includes/functions.php
+++ src/wp-includes/functions.php
@@ -1221,7 +1221,7 @@ function do_feed() {
 	 * search result, or main comments. By checking for the absense of posts we can prevent rendering the feed
 	 * templates at invalid endpoints. e.g.) /wp-content/plugins/feed/
 	 */
-	if ( ! $wp_query->have_posts() && ! ( $wp_query->is_archive() || $wp_query->is_search() || $is_main_comments_feed ) ) {
+	if ( ! $wp_query->have_posts() && ! ( $wp_query->is_archive() || $wp_query->is_search() || $is_main_comments_feed || $wp_query->is_home_feed() || $wp_query->is_custom_feed() ) ) {
 		wp_die( __( 'ERROR: This is not a valid feed.' ), '', array( 'response' => 404 ) );
 	}
 
diff --git src/wp-includes/query.php src/wp-includes/query.php
index 744610f..db399f1 100644
--- src/wp-includes/query.php
+++ src/wp-includes/query.php
@@ -383,6 +383,46 @@ function is_comment_feed() {
 }
 
 /**
+ * Is the query for the blog homepage feed?
+ *
+ * @since 4.7.1
+ *
+ * @global WP_Query $wp_query Global WP_Query instance.
+ *
+ * @return bool
+ */
+function is_home_feed() {
+	global $wp_query;
+
+	if ( ! isset( $wp_query ) ) {
+		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
+		return false;
+	}
+
+	return $wp_query->is_home_feed();
+}
+
+/**
+ * Is the query for the custom feed?
+ *
+ * @since 4.7.1
+ *
+ * @global WP_Query $wp_query Global WP_Query instance.
+ *
+ * @return bool
+ */
+function is_custom_feed() {
+	global $wp_query;
+
+	if ( ! isset( $wp_query ) ) {
+		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
+		return false;
+	}
+
+	return $wp_query->is_custom_feed();
+}
+
+/**
  * Is the query for the front page of the site?
  *
  * This is for what is displayed at your site's main URL.
diff --git tests/phpunit/includes/testcase.php tests/phpunit/includes/testcase.php
index 8990504..681bcd0 100644
--- tests/phpunit/includes/testcase.php
+++ tests/phpunit/includes/testcase.php
@@ -597,6 +597,8 @@ class WP_UnitTestCase extends PHPUnit_Framework_TestCase {
 			'is_day',
 			'is_embed',
 			'is_feed',
+			'is_home_feed',
+			'is_custom_feed',
 			'is_front_page',
 			'is_home',
 			'is_month',
diff --git tests/phpunit/tests/feed/rss2.php tests/phpunit/tests/feed/rss2.php
index fab3726..dd13839 100644
--- tests/phpunit/tests/feed/rss2.php
+++ tests/phpunit/tests/feed/rss2.php
@@ -63,6 +63,10 @@ class Tests_Feeds_RSS2 extends WP_UnitTestCase {
 
 		$this->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' );
 		create_initial_taxonomies();
+
+		// Add a custom feed
+		add_feed( 'custom', 'do_rss2' );
+
 	}
 
 	/**
@@ -296,7 +300,7 @@ class Tests_Feeds_RSS2 extends WP_UnitTestCase {
 		$this->go_to( 'feed/' );
 
 		// Verify the query object is a feed.
-		$this->assertQueryTrue( 'is_feed' );
+		$this->assertQueryTrue( 'is_feed', 'is_home_feed' );
 
 		// Queries performed on valid feed endpoints should contain posts.
 		$this->assertTrue( have_posts() );
@@ -313,6 +317,25 @@ class Tests_Feeds_RSS2 extends WP_UnitTestCase {
 		$this->assertEquals( 1, count( $rss ) );
 	}
 
+	function test_valid_custom_feed_endpoint() {
+		// An example of a valid home feed endpoint.
+		$this->go_to( 'feed/custom' );
+
+		// Verify the query object is a feed.
+		$this->assertQueryTrue( 'is_feed', 'is_custom_feed' );
+
+		// Check to see if we have the expected XML output from the feed template.
+		$feed = $this->do_rss2();
+
+		$xml = xml_to_array( $feed );
+
+		// Get the <rss> child element of <xml>.
+		$rss = xml_find( $xml, 'rss' );
+
+		// There should only be one <rss> child element.
+		$this->assertEquals( 1, count( $rss ) );
+	}
+
 	/*
 	 * Check to make sure we are rendering feed templates for the taxonomy feeds.
 	 * e.g. https://example.com/category/foo/feed/
@@ -408,7 +431,7 @@ class Tests_Feeds_RSS2 extends WP_UnitTestCase {
 	 *
 	 * @ticket 30210
 	 */
-	function test_valid_single_post_comment_feed_endpoint() {
+	function test_valid_singular_comment_feed_endpoint() {
 		// An example of an valid date archive feed endpoint.
 		$this->go_to( get_post_comments_feed_link( self::$posts[0] ) );
 
diff --git tests/phpunit/tests/query/conditionals.php tests/phpunit/tests/query/conditionals.php
index 8cceaa5..323ba67 100644
--- tests/phpunit/tests/query/conditionals.php
+++ tests/phpunit/tests/query/conditionals.php
@@ -253,13 +253,13 @@ class Tests_Query_Conditionals extends WP_UnitTestCase {
 		// long version
 		foreach ($feeds as $feed) {
 			$this->go_to("/feed/{$feed}/");
-			$this->assertQueryTrue('is_feed');
+			$this->assertQueryTrue('is_feed', 'is_home_feed');
 		}
 
 		// short version
 		foreach ($feeds as $feed) {
 			$this->go_to("/{$feed}/");
-			$this->assertQueryTrue('is_feed');
+			$this->assertQueryTrue('is_feed', 'is_home_feed');
 		}
 
 	}
@@ -269,7 +269,7 @@ class Tests_Query_Conditionals extends WP_UnitTestCase {
 		$types = array('rss2', 'rss', 'atom');
 		foreach ($types as $type) {
 			$this->go_to(get_feed_link($type));
-			$this->assertQueryTrue('is_feed');
+			$this->assertQueryTrue('is_feed', 'is_home_feed');
 		}
 	}
 
@@ -369,6 +369,22 @@ class Tests_Query_Conditionals extends WP_UnitTestCase {
 		}
 	}
 
+	function test_invalid_category_feed() {
+		// check the long form
+		$types = array( 'feed', 'rdf', 'rss', 'rss2', 'atom' );
+		foreach ( $types as $type ) {
+			$this->go_to( "/category/four-oh-four-cat/feed/{$type}/" );
+			$this->assertQueryTrue( 'is_404' );
+		}
+
+		// check the short form
+		$types = array( 'feed', 'rdf', 'rss', 'rss2', 'atom' );
+		foreach ( $types as $type ) {
+			$this->go_to( "/category/four-oh-four-cat/{$type}/" );
+			$this->assertQueryTrue( 'is_404' );
+		}
+	}
+
 	// 'category/(.+?)/page/?([0-9]{1,})/?$' => 'index.php?category_name=$matches[1]&paged=$matches[2]',
 	function test_category_paged() {
 		update_option( 'posts_per_page', 2 );
