diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5426675d0db2ab81f1345a55f4d7a99019237f8a..257a75068ee8e240a993c2bd213f919dc577373b 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -840,6 +840,7 @@ if (BUILD_TESTS)
         SOURCES ProducerConsumerQueueTest.cpp
       TEST random_test SOURCES RandomTest.cpp
       TEST range_test SOURCES RangeTest.cpp
+      TEST replaceable_test SOURCES ReplaceableTest.cpp
       TEST scope_guard_test SOURCES ScopeGuardTest.cpp
       # Heavily dependent on drand and srand48
       #TEST shared_mutex_test SOURCES SharedMutexTest.cpp
diff --git a/folly/Replaceable.h b/folly/Replaceable.h
index abb79c9141b5a259a7c57e9ce8ddfae415680ca8..cbecb54f37da9157b08e20ebcc2f59b6e33a86ab 100644
--- a/folly/Replaceable.h
+++ b/folly/Replaceable.h
@@ -595,11 +595,8 @@ class alignas(T) Replaceable
 
   /**
    * `swap` just calls `swap(T&, T&)`.
-   *
-   * Should be `noexcept(std::is_nothrow_swappable<T>::value)` but we don't
-   * depend on C++17 features.
    */
-  void swap(Replaceable& other) {
+  void swap(Replaceable& other) noexcept(IsNothrowSwappable<Replaceable>{}) {
     using std::swap;
     swap(*(*this), *other);
   }
diff --git a/folly/test/ReplaceableTest.cpp b/folly/test/ReplaceableTest.cpp
index af3c4bdcda4c3d861ce0a1acfd49897bead23d2a..f3aca572274982a68e8233c406c7b973e11b4f67 100644
--- a/folly/test/ReplaceableTest.cpp
+++ b/folly/test/ReplaceableTest.cpp
@@ -44,7 +44,9 @@ struct HasRef final {
     ++i1;
   }
 };
-
+void swap(HasRef& lhs, HasRef& rhs) noexcept(false) {
+  std::swap(lhs.i1, rhs.i1);
+}
 struct OddA;
 struct OddB {
   OddB() = delete;
@@ -70,6 +72,11 @@ struct OddA {
 struct Indestructible {
   ~Indestructible() = delete;
 };
+
+struct HasInt {
+  explicit HasInt(int v) : value{v} {}
+  int value{};
+};
 } // namespace
 
 template <typename T>
@@ -289,3 +296,41 @@ TEST(ReplaceableTest, Conversions) {
   Replaceable<OddA> rOddA{std::move(rOddB)};
   Replaceable<OddB> rOddB2{rOddA};
 }
+
+TEST(ReplaceableTest, swapMemberFunctionIsNoexcept) {
+  int v1{1};
+  int v2{2};
+  auto r1 = Replaceable<HasInt>{v1};
+  auto r2 = Replaceable<HasInt>{v2};
+  EXPECT_TRUE(noexcept(r1.swap(r2)));
+  r1.swap(r2);
+  EXPECT_EQ(v2, r1->value);
+  EXPECT_EQ(v1, r2->value);
+}
+
+TEST(ReplaceableTest, swapMemberFunctionIsNotNoexcept) {
+  int v1{1};
+  int v2{2};
+  auto r1 = Replaceable<HasRef>{v1};
+  auto r2 = Replaceable<HasRef>{v2};
+  EXPECT_FALSE(noexcept(r1.swap(r2)));
+  r1.swap(r2);
+  EXPECT_EQ(v1, r1->i1);
+  EXPECT_EQ(v2, r2->i1);
+}
+
+namespace adl_test {
+struct UserDefinedSwap {
+  bool calledSwap{};
+};
+void swap(UserDefinedSwap& lhs, UserDefinedSwap&) noexcept(false) {
+  lhs.calledSwap = true;
+}
+} // namespace adl_test
+
+TEST(ReplaceableTest, swapMemberFunctionDelegatesToUserSwap) {
+  auto r1 = Replaceable<adl_test::UserDefinedSwap>{};
+  auto r2 = Replaceable<adl_test::UserDefinedSwap>{};
+  r1.swap(r2);
+  EXPECT_TRUE(r1->calledSwap);
+}