diff --git a/src/operations.cpp b/src/operations.cpp
index 9184b37..09b8853 100644
--- a/src/operations.cpp
+++ b/src/operations.cpp
@@ -775,6 +775,7 @@ namespace detail
   path canonical(const path& p, const path& base, system::error_code* ec)
   {
     path source (p.is_absolute() ? p : absolute(p, base));
+    path root(source.root_path());
     path result;
 
     system::error_code local_ec;
@@ -809,7 +810,8 @@ namespace detail
           continue;
         if (*itr == dot_dot_path)
         {
-          result.remove_filename();
+          if (result != root)
+            result.remove_filename();
           continue;
         }
 
diff --git a/test/operations_test.cpp b/test/operations_test.cpp
index dccd765..8974b5e 100644
--- a/test/operations_test.cpp
+++ b/test/operations_test.cpp
@@ -1423,6 +1423,32 @@ namespace
     BOOST_TEST_EQ(fs::canonical(relative_dir / "f0"), dir / "f0");
     BOOST_TEST_EQ(fs::canonical(relative_dir / "./f0"), dir / "f0");
     BOOST_TEST_EQ(fs::canonical(relative_dir / "d1/../f0"), dir / "f0");
+
+    // treat parent of root as itself on both POSIX and Windows
+    fs::path init(fs::initial_path());
+    fs::path root(init.root_path());
+    fs::path::const_iterator it(init.begin());
+    fs::path first;   // relative first non-root directory
+#  ifdef BOOST_WINDOWS_API
+    if (!init.empty())
+      ++it;
+#  endif
+    if (++it != init.end())
+      first = *it;
+    fs::path expected(root/first);
+
+    cout << "init: " << init << endl;
+    cout << "root: " << root << endl;
+    cout << "first: " << first << endl;
+    cout << "expected: " << expected << endl;
+
+    //  ticket 10187 tests
+    BOOST_TEST_EQ(fs::canonical(root / "../.." / first), expected);
+    BOOST_TEST_EQ(fs::canonical(fs::path("../..") / first, root), expected);
+    BOOST_TEST_EQ(fs::canonical(fs::path("/../..") / first, fs::current_path().root_name()), expected);
+
+    //  ticket 9683 test
+    BOOST_TEST_EQ(fs::canonical(root / first / "../../../../.."), root);
   }
 
   //  canonical_symlink_tests  -----------------------------------------------------------//
@@ -1925,7 +1951,7 @@ int cpp_main(int argc, char* argv[])
       skip_long_windows_tests = true;
   }
 
-  // The choice of platform to test is make at runtime rather than compile-time
+  // The choice of platform to test is made at runtime rather than compile-time
   // so that compile errors for all platforms will be detected even though
   // only the current platform is runtime tested.
 # if defined(BOOST_POSIX_API)
@@ -1941,6 +1967,16 @@ int cpp_main(int argc, char* argv[])
 #   error neither BOOST_POSIX_API nor BOOST_WINDOWS_API is defined. See boost/system/api_config.hpp
 # endif
   cout << "API is " << platform << endl;
+  cout << "initial_path() is " << fs::initial_path() << endl;
+  fs::path ip = fs::initial_path();
+
+  for (fs::path::const_iterator it = ip.begin(); it != ip.end(); ++it)
+  {
+    if (it != ip.begin())
+      cout << ", ";
+    cout << *it;
+  }
+  cout << endl;
 
   dir = fs::initial_path() / temp_dir;