diff --git a/configure/E3/CONFIG b/configure/E3/CONFIG
index 4de30799f81ad90e4f5c9e183847cc93fec76f5f..d1e4bd8e77436c59bb690148ab372b4f17f4373c 100644
--- a/configure/E3/CONFIG
+++ b/configure/E3/CONFIG
@@ -10,6 +10,7 @@ include $(EPICS_BASE)/configure/CONFIG_BASE_VERSION
 include $(E3_REQUIRE_CONFIG)/CONFIG_REQUIRE
 include $(E3_REQUIRE_CONFIG)/CONFIG_SHELL
 include $(E3_REQUIRE_CONFIG)/CONFIG_CELL
+include $(E3_REQUIRE_CONFIG)/CONFIG_PATCH
 include $(E3_REQUIRE_CONFIG)/CONFIG_TEST
 include $(E3_REQUIRE_CONFIG)/CONFIG_E3_PATH
 include $(E3_REQUIRE_CONFIG)/CONFIG_E3_MAKEFILE
diff --git a/configure/E3/CONFIG_PATCH b/configure/E3/CONFIG_PATCH
new file mode 100644
index 0000000000000000000000000000000000000000..6dc049607327468fe8789c62fd41b6c0d11f8ea2
--- /dev/null
+++ b/configure/E3/CONFIG_PATCH
@@ -0,0 +1,3 @@
+# We want to sort these alphabetically to allow for defined ordering of application of patches.
+# Note that make 4.3 onwards sorts correctly, but not necessarily the version we use.
+PATCHES:=$(shell ls $(TOP)/patch/*.p0.patch 2> /dev/null)
diff --git a/configure/E3/RULES_PATCH b/configure/E3/RULES_PATCH
index 3b0cdd43ae88f0068f50ec56282a727de9d76d85..67212c8e90ac2f74049b71f5d983dc4766cbceeb 100644
--- a/configure/E3/RULES_PATCH
+++ b/configure/E3/RULES_PATCH
@@ -3,4 +3,19 @@
 
 ## Apply Patch Files
 patch:
-	$(QUIET) $(call patch_site)
+
+define PATCH_TEMPLATE
+patch: $1
+.PHONY: $1
+$1:
+	@echo "Applying patch $$@"
+	git apply --directory=$$(E3_MODULE_SRC_PATH) --ignore-whitespace -p0 $$@
+endef
+
+ifneq ($(strip $(PATCHES)),)
+$(foreach patch,$(PATCHES),$(eval $(call PATCH_TEMPLATE,$(patch))))
+else
+patch:
+	@echo "No patches to apply"
+
+endif
diff --git a/tests/test_build.py b/tests/test_build.py
index 6c24f3cbc97ecf891c8682668e2e269c81d067ae..283ad8f5731b21ee7d51f2e5dfa7fd61a3349820 100644
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -11,21 +11,20 @@ RE_MISSING_VERSION = "Module '{module}' version '{version}' does not exist."
 RE_MODULE_VERSION_EXISTS = "Error .*{module}/{version}.* already exists"
 
 
-def create_patch_file(path, desc):
+def create_patch_file(path: Path, filename: str, desc: str):
     path.parent.mkdir(parents=True, exist_ok=True)
     patch_file_contents = """
-diff --git database.db database.db
+diff --git {filename} {filename}
 index 1806ff6..8701832 100644
---- database.db
-+++ database.db
+--- {filename}
++++ {filename}
 @@ -1,3 +1,3 @@
  record(ai, "TEST") {{
 -
 +    field(DESC, "{desc}")
  }}
 """
-    with open(path, "w") as f:
-        f.write(patch_file_contents.format(desc=desc))
+    path.write_text(patch_file_contents.format(filename=filename, desc=desc))
 
 
 def test_patch(wrapper: Wrapper):
@@ -38,8 +37,10 @@ def test_patch(wrapper: Wrapper):
         f.write(db_file_contents)
 
     patch_dir = wrapper.path / "patch"
-    create_patch_file(patch_dir / "apply.p0.patch", "OK")
-    create_patch_file(patch_dir / wrapper.version / "do-not-apply.p0.patch", "Bad")
+    create_patch_file(patch_dir / "apply.p0.patch", "database.db", "OK")
+    create_patch_file(
+        patch_dir / wrapper.version / "do-not-apply.p0.patch", "database.db", "Bad"
+    )
 
     rc, _, _ = wrapper.run_make("patch")
     assert rc == 0
@@ -57,6 +58,29 @@ def test_patch(wrapper: Wrapper):
     assert any((wrapper.path / "cellMods").glob("**/*.db"))
 
 
+@pytest.mark.parametrize("good_patch_first", [True, False])
+def test_patch_failure(wrapper: Wrapper, good_patch_first):
+    db_path = wrapper.module_dir / "database.db"
+    db_file_contents = """record(ai, "TEST") {
+
+}
+"""
+    db_path.write_text(db_file_contents)
+
+    patch_dir = wrapper.path / "patch"
+    good_patch_order, bad_patch_order = (1, 2) if good_patch_first else (2, 1)
+    create_patch_file(
+        patch_dir / f"{good_patch_order}_good.p0.patch", "database.db", "OK"
+    )
+    create_patch_file(
+        patch_dir / f"{bad_patch_order}_bad.p0.patch", "not_a_file", "this_should_fail"
+    )
+
+    rc, _, errs = wrapper.run_make("patch")
+    assert rc == 2
+    assert "not_a_file: No such file or directory" in errs
+
+
 def test_local_module(wrapper: Wrapper):
     rc, outs, _ = wrapper.run_make("init")
     assert rc == 0