diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 91f08e64da759f92acffc031cbf301f2ab3a77fe..51175c7e0a73d6f548c392272f6fe99ba81ea3e9 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -493,6 +493,8 @@ void cmGlobalNinjaGenerator::Generate()
   this->OpenBuildFileStream();
   this->OpenRulesFileStream();
 
+  this->TargetDependsClosures.clear();
+
   this->InitOutputPathPrefix();
   this->TargetAll = this->NinjaOutputPath("all");
   this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt");
@@ -905,6 +907,42 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
   }
 }
 
+void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
+  cmGeneratorTarget const* target, cmNinjaDeps& outputs)
+{
+  TargetDependsClosureMap::iterator i =
+    this->TargetDependsClosures.find(target);
+  if (i == this->TargetDependsClosures.end()) {
+    TargetDependsClosureMap::value_type e(
+      target, std::set<cmGeneratorTarget const*>());
+    i = this->TargetDependsClosures.insert(e).first;
+    this->ComputeTargetDependsClosure(target, i->second);
+  }
+  std::set<cmGeneratorTarget const*> const& targets = i->second;
+  cmNinjaDeps outs;
+  for (std::set<cmGeneratorTarget const*>::const_iterator ti = targets.begin();
+       ti != targets.end(); ++ti) {
+    this->AppendTargetOutputs(*ti, outs);
+  }
+  std::sort(outs.begin(), outs.end());
+  outputs.insert(outputs.end(), outs.begin(), outs.end());
+}
+
+void cmGlobalNinjaGenerator::ComputeTargetDependsClosure(
+  cmGeneratorTarget const* target, std::set<cmGeneratorTarget const*>& depends)
+{
+  cmTargetDependSet const& targetDeps = this->GetTargetDirectDepends(target);
+  for (cmTargetDependSet::const_iterator i = targetDeps.begin();
+       i != targetDeps.end(); ++i) {
+    if ((*i)->GetType() == cmState::INTERFACE_LIBRARY) {
+      continue;
+    }
+    if (depends.insert(*i).second) {
+      this->ComputeTargetDependsClosure(*i, depends);
+    }
+  }
+}
+
 void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias,
                                             cmGeneratorTarget* target)
 {
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index c74973e17534dd9da9af9788bbbfcecb1b64bfc1..52fa5c9556579a3589b5a493dcbec09d14325e6d 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -301,6 +301,8 @@ public:
                            cmNinjaDeps& outputs);
   void AppendTargetDepends(cmGeneratorTarget const* target,
                            cmNinjaDeps& outputs);
+  void AppendTargetDependsClosure(cmGeneratorTarget const* target,
+                                  cmNinjaDeps& outputs);
   void AddDependencyToAll(cmGeneratorTarget* target);
   void AddDependencyToAll(const std::string& input);
 
@@ -361,6 +363,10 @@ private:
   void WriteTargetClean(std::ostream& os);
   void WriteTargetHelp(std::ostream& os);
 
+  void ComputeTargetDependsClosure(
+    cmGeneratorTarget const* target,
+    std::set<cmGeneratorTarget const*>& depends);
+
   std::string ninjaCmd() const;
 
   /// The file containing the build statement. (the relationship of the
@@ -410,6 +416,11 @@ private:
   typedef std::map<std::string, cmGeneratorTarget*> TargetAliasMap;
   TargetAliasMap TargetAliases;
 
+  typedef std::map<cmGeneratorTarget const*,
+                   std::set<cmGeneratorTarget const*> >
+    TargetDependsClosureMap;
+  TargetDependsClosureMap TargetDependsClosures;
+
   std::string NinjaCommand;
   std::string NinjaVersion;
 
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 0f488a6a86a9ed9261bfa2434a18f91efa38d5bb..46d7e18cf6572b1d295d969e7bca513dd77c6a85 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -450,13 +450,14 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements()
     std::set<cmGeneratorTarget*>::iterator j = i->second.begin();
     assert(j != i->second.end());
     std::vector<std::string> ccTargetDeps;
-    this->AppendTargetDepends(*j, ccTargetDeps);
+    this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j,
+                                                                ccTargetDeps);
     std::sort(ccTargetDeps.begin(), ccTargetDeps.end());
     ++j;
 
     for (; j != i->second.end(); ++j) {
       std::vector<std::string> jDeps, depsIntersection;
-      this->AppendTargetDepends(*j, jDeps);
+      this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j, jDeps);
       std::sort(jDeps.begin(), jDeps.end());
       std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(),
                             jDeps.begin(), jDeps.end(),
diff --git a/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake
index 92c4a38fed1f3ecd3b648344b59b2576a999261e..6c4e91bcaf7a7ed2646c24cc28e17f526bd33519 100644
--- a/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake
+++ b/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake
@@ -4,3 +4,17 @@ run_cmake(NoArguments)
 run_cmake(BadTargetName)
 run_cmake(ByproductsNoCommand)
 run_cmake(UsesTerminalNoCommand)
+
+function(run_TargetOrder)
+  # Use a single build tree for a few tests without cleaning.
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TargetOrder-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  run_cmake(TargetOrder)
+  if(RunCMake_GENERATOR STREQUAL "Ninja")
+    set(build_flags -j 1 -v)
+  endif()
+  run_cmake_command(TargetOrder-build ${CMAKE_COMMAND} --build . -- ${build_flags})
+endfunction()
+run_TargetOrder()
diff --git a/Tests/RunCMake/add_custom_target/TargetOrder.cmake b/Tests/RunCMake/add_custom_target/TargetOrder.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..21669c01121ce4072b49ec7b2cd461bba93c6454
--- /dev/null
+++ b/Tests/RunCMake/add_custom_target/TargetOrder.cmake
@@ -0,0 +1,31 @@
+# Add a target that requires step1 to run first but enforces
+# it only by target-level ordering dependency.
+add_custom_command(
+  OUTPUT step2.txt
+  COMMAND ${CMAKE_COMMAND} -E copy step1.txt step2.txt
+  )
+add_custom_target(step2 DEPENDS step2.txt)
+add_dependencies(step2 step1)
+
+# Add a target that requires step1 and step2 to work,
+# only depends on step1 transitively through step2, but
+# also gets a copy of step2's custom command.
+# The Ninja generator in particular must be careful with
+# this case because it needs to compute the proper set of
+# target ordering dependencies for the step2 custom command
+# even though it appears in both the step2 and step3
+# targets due to dependency propagation.
+add_custom_command(
+  OUTPUT step3.txt
+  COMMAND ${CMAKE_COMMAND} -E copy step1.txt step3-1.txt
+  COMMAND ${CMAKE_COMMAND} -E copy step2.txt step3.txt
+  DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/step2.txt
+  )
+add_custom_target(step3 ALL DEPENDS step3.txt)
+add_dependencies(step3 step2)
+
+# We want this target to always run first.  Add it last so
+# that serial builds require dependencies to order it first.
+add_custom_target(step1
+  COMMAND ${CMAKE_COMMAND} -E touch step1.txt
+  )