diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 3b49f72ddc3faf7e0ca98a8d2f0eb1e303749b4d..76b98fcf81a12c3c14debba3d63864aa4ef59d97 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -639,6 +639,7 @@ if(APPLE)
   set(SRCS ${SRCS}
     cmXCodeObject.cxx
     cmXCode21Object.cxx
+    cmXCodeScheme.cxx
     cmGlobalXCodeGenerator.cxx
     cmGlobalXCodeGenerator.h
     cmLocalXCodeGenerator.cxx
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 8627cf282013189040064789f3a2211d57cdeddd..8acea45e16734db12023e812c54113e40f177f15 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -28,6 +28,7 @@
 #include "cmTarget.h"
 #include "cmXCode21Object.h"
 #include "cmXCodeObject.h"
+#include "cmXCodeScheme.h"
 #include "cm_auto_ptr.hxx"
 #include "cmake.h"
 
@@ -3327,6 +3328,15 @@ void cmGlobalXCodeGenerator::OutputXCodeProject(
     return;
   }
   this->WriteXCodePBXProj(fout, root, generators);
+
+  // Since the lowest available Xcode version for testing was 7.0,
+  // I'm setting this as a limit then
+  if (this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool(
+        "XCODE_GENERATE_SCHEME") &&
+      this->XcodeVersion >= 70) {
+    this->OutputXCodeSharedSchemes(xcodeDir, root);
+  }
+
   this->ClearXCodeObjects();
 
   // Since this call may have created new cache entries, save the cache:
@@ -3335,6 +3345,24 @@ void cmGlobalXCodeGenerator::OutputXCodeProject(
     root->GetBinaryDirectory());
 }
 
+void cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
+  const std::string& xcProjDir, cmLocalGenerator* root)
+{
+  for (std::vector<cmXCodeObject*>::const_iterator i =
+         this->XCodeObjects.begin();
+       i != this->XCodeObjects.end(); ++i) {
+    cmXCodeObject* obj = *i;
+    if (obj->GetType() == cmXCodeObject::OBJECT &&
+        (obj->GetIsA() == cmXCodeObject::PBXNativeTarget ||
+         obj->GetIsA() == cmXCodeObject::PBXAggregateTarget)) {
+      cmXCodeScheme schm(obj, this->CurrentConfigurationTypes,
+                         this->XcodeVersion);
+      schm.WriteXCodeSharedScheme(xcProjDir,
+                                  root->GetCurrentSourceDirectory());
+    }
+  }
+}
+
 void cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
                                                cmLocalGenerator*,
                                                std::vector<cmLocalGenerator*>&)
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 1aaf9c709bd3940c6d8b7e126204dd70e4686b96..c9157b06ecb504e3ae67faa90046ebaeeae50a37 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -165,6 +165,9 @@ private:
                           std::vector<cmLocalGenerator*>& generators);
   void OutputXCodeProject(cmLocalGenerator* root,
                           std::vector<cmLocalGenerator*>& generators);
+  // Write shared scheme files for all the native targets
+  void OutputXCodeSharedSchemes(const std::string& xcProjDir,
+                                cmLocalGenerator* root);
   void WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* root,
                          std::vector<cmLocalGenerator*>& generators);
   cmXCodeObject* CreateXCodeFileReferenceFromPath(const std::string& fullpath,
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3c8c0b77792f21d03de11f48c59d909f758dfaab
--- /dev/null
+++ b/Source/cmXCodeScheme.cxx
@@ -0,0 +1,206 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmXCodeScheme.h"
+
+#include <iomanip>
+#include <sstream>
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmXMLSafe.h"
+
+cmXCodeScheme::cmXCodeScheme(cmXCodeObject* xcObj,
+                             const std::vector<std::string>& configList,
+                             unsigned int xcVersion)
+  : TargetName(xcObj->GetTarget()->GetName())
+  , TargetId(xcObj->GetId())
+  , ConfigList(configList)
+  , XcodeVersion(xcVersion)
+{
+}
+
+void cmXCodeScheme::WriteXCodeSharedScheme(const std::string& xcProjDir,
+                                           const std::string sourceRoot)
+{
+  // Create shared scheme sub-directory tree
+  //
+  std::string xcodeSchemeDir = xcProjDir;
+  xcodeSchemeDir += "/xcshareddata/xcschemes";
+  cmSystemTools::MakeDirectory(xcodeSchemeDir.c_str());
+
+  std::string xcodeSchemeFile = xcodeSchemeDir;
+  xcodeSchemeFile += "/";
+  xcodeSchemeFile += this->TargetName;
+  xcodeSchemeFile += ".xcscheme";
+
+  cmGeneratedFileStream fout(xcodeSchemeFile.c_str());
+  fout.SetCopyIfDifferent(true);
+  if (!fout) {
+    return;
+  }
+
+  std::string xcProjRelDir = xcProjDir.substr(sourceRoot.size() + 1);
+  WriteXCodeXCScheme(fout, xcProjRelDir);
+}
+
+void cmXCodeScheme::WriteXCodeXCScheme(std::ostream& fout,
+                                       const std::string& xcProjDir)
+{
+  cmXMLWriter xout(fout);
+  xout.StartDocument();
+
+  xout.StartElement("Scheme");
+  xout.BreakAttributes();
+  xout.Attribute("LastUpgradeVersion", WriteVersionString());
+  xout.Attribute("version", "1.3");
+
+  WriteBuildAction(xout, xcProjDir);
+  WriteTestAction(xout, FindConfiguration("Debug"));
+  WriteLaunchAction(xout, FindConfiguration("Debug"), xcProjDir);
+  WriteProfileAction(xout, FindConfiguration("Release"));
+  WriteAnalyzeAction(xout, FindConfiguration("Debug"));
+  WriteArchiveAction(xout, FindConfiguration("Release"));
+
+  xout.EndElement();
+}
+
+void cmXCodeScheme::WriteBuildAction(cmXMLWriter& xout,
+                                     const std::string& xcProjDir)
+{
+  xout.StartElement("BuildAction");
+  xout.BreakAttributes();
+  xout.Attribute("parallelizeBuildables", "YES");
+  xout.Attribute("buildImplicitDependencies", "YES");
+
+  xout.StartElement("BuildActionEntries");
+  xout.StartElement("BuildActionEntry");
+  xout.BreakAttributes();
+  xout.Attribute("buildForTesting", "YES");
+  xout.Attribute("buildForRunning", "YES");
+  xout.Attribute("buildForProfiling", "YES");
+  xout.Attribute("buildForArchiving", "YES");
+  xout.Attribute("buildForAnalyzing", "YES");
+
+  xout.StartElement("BuildableReference");
+  xout.BreakAttributes();
+  xout.Attribute("BuildableIdentifier", "primary");
+  xout.Attribute("BlueprintIdentifier", this->TargetId);
+  xout.Attribute("BuildableName", this->TargetName);
+  xout.Attribute("BlueprintName", this->TargetName);
+  xout.Attribute("ReferencedContainer", "container:" + xcProjDir);
+  xout.EndElement();
+
+  xout.EndElement(); // BuildActionEntry
+  xout.EndElement(); // BuildActionEntries
+  xout.EndElement(); // BuildAction
+}
+
+void cmXCodeScheme::WriteTestAction(cmXMLWriter& xout,
+                                    std::string configuration)
+{
+  xout.StartElement("TestAction");
+  xout.BreakAttributes();
+  xout.Attribute("buildConfiguration", configuration);
+  xout.Attribute("selectedDebuggerIdentifier",
+                 "Xcode.DebuggerFoundation.Debugger.LLDB");
+  xout.Attribute("selectedLauncherIdentifier",
+                 "Xcode.DebuggerFoundation.Launcher.LLDB");
+  xout.Attribute("shouldUseLaunchSchemeArgsEnv", "YES");
+
+  xout.StartElement("Testables");
+  xout.EndElement();
+
+  xout.StartElement("AdditionalOptions");
+  xout.EndElement();
+
+  xout.EndElement(); // TestAction
+}
+
+void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
+                                      std::string configuration,
+                                      const std::string& xcProjDir)
+{
+  xout.StartElement("LaunchAction");
+  xout.BreakAttributes();
+  xout.Attribute("buildConfiguration", configuration);
+  xout.Attribute("selectedDebuggerIdentifier",
+                 "Xcode.DebuggerFoundation.Debugger.LLDB");
+  xout.Attribute("selectedLauncherIdentifier",
+                 "Xcode.DebuggerFoundation.Launcher.LLDB");
+  xout.Attribute("launchStyle", "0");
+  xout.Attribute("useCustomWorkingDirectory", "NO");
+  xout.Attribute("ignoresPersistentStateOnLaunch", "NO");
+  xout.Attribute("debugDocumentVersioning", "YES");
+  xout.Attribute("debugServiceExtension", "internal");
+  xout.Attribute("allowLocationSimulation", "YES");
+
+  xout.StartElement("MacroExpansion");
+
+  xout.StartElement("BuildableReference");
+  xout.BreakAttributes();
+  xout.Attribute("BuildableIdentifier", "primary");
+  xout.Attribute("BlueprintIdentifier", this->TargetId);
+  xout.Attribute("BuildableName", this->TargetName);
+  xout.Attribute("BlueprintName", this->TargetName);
+  xout.Attribute("ReferencedContainer", "container:" + xcProjDir);
+  xout.EndElement();
+
+  xout.EndElement(); // MacroExpansion
+
+  xout.StartElement("AdditionalOptions");
+  xout.EndElement();
+
+  xout.EndElement(); // LaunchAction
+}
+
+void cmXCodeScheme::WriteProfileAction(cmXMLWriter& xout,
+                                       std::string configuration)
+{
+  xout.StartElement("ProfileAction");
+  xout.BreakAttributes();
+  xout.Attribute("buildConfiguration", configuration);
+  xout.Attribute("shouldUseLaunchSchemeArgsEnv", "YES");
+  xout.Attribute("savedToolIdentifier", "");
+  xout.Attribute("useCustomWorkingDirectory", "NO");
+  xout.Attribute("debugDocumentVersioning", "YES");
+  xout.EndElement();
+}
+
+void cmXCodeScheme::WriteAnalyzeAction(cmXMLWriter& xout,
+                                       std::string configuration)
+{
+  xout.StartElement("AnalyzeAction");
+  xout.BreakAttributes();
+  xout.Attribute("buildConfiguration", configuration);
+  xout.EndElement();
+}
+
+void cmXCodeScheme::WriteArchiveAction(cmXMLWriter& xout,
+                                       std::string configuration)
+{
+  xout.StartElement("ArchiveAction");
+  xout.BreakAttributes();
+  xout.Attribute("buildConfiguration", configuration);
+  xout.Attribute("revealArchiveInOrganizer", "YES");
+  xout.EndElement();
+}
+
+std::string cmXCodeScheme::WriteVersionString()
+{
+  std::ostringstream v;
+  v << std::setfill('0') << std::setw(4) << this->XcodeVersion * 10;
+  return v.str();
+}
+
+std::string cmXCodeScheme::FindConfiguration(const std::string& name)
+{
+  // Try to find the desired configuration by name,
+  // and if it's not found return first from the list
+  //
+  if (std::find(this->ConfigList.begin(), this->ConfigList.end(), name) ==
+        this->ConfigList.end() &&
+      this->ConfigList.size() > 0)
+    return this->ConfigList[0];
+
+  return name;
+}
diff --git a/Source/cmXCodeScheme.h b/Source/cmXCodeScheme.h
new file mode 100644
index 0000000000000000000000000000000000000000..b174c51b572dde3910a47621809bda95df158810
--- /dev/null
+++ b/Source/cmXCodeScheme.h
@@ -0,0 +1,46 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmXCodeScheme_h
+#define cmXCodeScheme_h
+
+#include <cmConfigure.h> // IWYU pragma: keep
+
+#include "cmGlobalXCodeGenerator.h"
+#include "cmSystemTools.h"
+#include "cmXCodeObject.h"
+#include "cmXMLWriter.h"
+
+/** \class cmXCodeScheme
+ * \brief Write shared schemes for native targets in Xcode project.
+ */
+class cmXCodeScheme
+{
+public:
+  cmXCodeScheme(cmXCodeObject* xcObj,
+                const std::vector<std::string>& configList,
+                unsigned int xcVersion);
+
+  void WriteXCodeSharedScheme(const std::string& xcProjDir,
+                              const std::string sourceRoot);
+
+private:
+  const std::string& TargetName;
+  const std::string& TargetId;
+  const std::vector<std::string>& ConfigList;
+  const unsigned int XcodeVersion;
+
+  void WriteXCodeXCScheme(std::ostream& fout, const std::string& xcProjDir);
+
+  void WriteBuildAction(cmXMLWriter& xout, const std::string& xcProjDir);
+  void WriteTestAction(cmXMLWriter& xout, std::string configuration);
+  void WriteLaunchAction(cmXMLWriter& xout, std::string configuration,
+                         const std::string& xcProjDir);
+  void WriteProfileAction(cmXMLWriter& xout, std::string configuration);
+  void WriteAnalyzeAction(cmXMLWriter& xout, std::string configuration);
+  void WriteArchiveAction(cmXMLWriter& xout, std::string configuration);
+
+  std::string WriteVersionString();
+  std::string FindConfiguration(const std::string& name);
+};
+
+#endif