diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java
index ebac3ceaa5ab8..a3f5ecaee63ef 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java
@@ -108,6 +108,17 @@
  * deletion without notice.</b>
  */
 public class JavacFiler implements Filer, Closeable {
+
+    protected static final Context.Key<JavacFiler> filerKey = new Context.Key<>();
+
+    /** Get the JavacFiler instance for this context. */
+    public static JavacFiler instance(Context context) {
+        JavacFiler instance = context.get(filerKey);
+        if (instance == null)
+            instance = new JavacFiler(context);
+        return instance;
+    }
+
     // TODO: Implement different transaction model for updating the
     // Filer's record keeping on file close.
 
@@ -398,7 +409,9 @@ public synchronized void close() throws IOException {
 
     private final String defaultTargetModule;
 
-    JavacFiler(Context context) {
+    protected JavacFiler(Context context) {
+        context.put(filerKey, this);
+
         this.context = context;
         fileManager = context.get(JavaFileManager.class);
         elementUtils = JavacElements.instance(context);
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
index 15329912c29df..f5ded440d889c 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
@@ -224,7 +224,7 @@ protected JavacProcessingEnvironment(Context context) {
 
         // Initialize services before any processors are initialized
         // in case processors use them.
-        filer = new JavacFiler(context);
+        filer = JavacFiler.instance(context);
         messager = new JavacMessager(context, this);
         elementUtils = JavacElements.instance(context);
         typeUtils = JavacTypes.instance(context);
diff --git a/test/langtools/tools/javac/processing/filer/TestFilerAsAService.java b/test/langtools/tools/javac/processing/filer/TestFilerAsAService.java
new file mode 100644
index 0000000000000..b5bb13c90ab12
--- /dev/null
+++ b/test/langtools/tools/javac/processing/filer/TestFilerAsAService.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8274817
+ * @summary Verify JavacFiler is subclassable, and can be registered as a service into Context.
+ * @library /tools/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.processing
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build toolbox.TestRunner toolbox.ToolBox TestFilerAsAService
+ * @run main TestFilerAsAService
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Base64;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.SupportedOptions;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.PackageElement;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import javax.tools.StandardLocation;
+
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.processing.JavacFiler;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Context.Factory;
+import java.util.*;
+
+import toolbox.JavacTask;
+import toolbox.TestRunner;
+import toolbox.TestRunner.Test;
+import toolbox.ToolBox;
+import toolbox.ToolBox.MemoryFileManager;
+
+public class TestFilerAsAService extends TestRunner {
+
+    public static void main(String... args) throws Exception {
+        new TestFilerAsAService().runTests(m -> new Object[] { Paths.get(m.getName()) });
+    }
+
+    private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+    private final ToolBox tb = new ToolBox();
+
+    public TestFilerAsAService() {
+        super(System.err);
+    }
+
+    @Test
+    public void testOriginatingElements(Path outerBase) throws Exception {
+        Path libSrc = outerBase.resolve("lib-src");
+        tb.writeJavaFiles(libSrc,
+                          """
+                          module lib { exports lib1; exports lib2; }
+                          """,
+                          """
+                          package lib1;
+                          public @interface A {
+                          }
+                          """,
+                          """
+                          package lib2;
+                          public class Lib {
+                          }
+                          """);
+        tb.writeFile(libSrc.resolve("lib1/package-info.java"), "@A package lib1;");
+        Path libClasses = outerBase.resolve("lib-classes");
+        Path libClassesModule = libClasses.resolve("lib");
+        Files.createDirectories(libClassesModule);
+
+        List<String> log = new ArrayList<>();
+
+        new JavacTask(tb)
+                .files(tb.findJavaFiles(libSrc))
+                .outdir(libClassesModule)
+                .run();
+
+        Path src = outerBase.resolve("src");
+        tb.writeJavaFiles(src,
+                          """
+                          module m {}
+                          """,
+                          """
+                          package t;
+                          public class T1 {
+                          }
+                          """,
+                          """
+                          package t;
+                          public class T2 {
+                          }
+                          """,
+                          """
+                          package t;
+                          public class T3 {
+                          }
+                          """);
+        tb.writeFile(src.resolve("p/package-info.java"), "package p;");
+        Path classes = outerBase.resolve("classes");
+        Files.createDirectories(classes);
+        try (StandardJavaFileManager sjfm = compiler.getStandardFileManager(null, null, null)) {
+            List<String> testOutput = new ArrayList<>();
+            try {
+                String generatedData;
+                try (MemoryFileManager mfm = new MemoryFileManager(sjfm)) {
+                    compiler.getTask(null, mfm, null, null, null,
+                                     List.of(new ToolBox.JavaSource("package test; public class Generated2 {}")))
+                            .call();
+                    generatedData =
+                            Base64.getEncoder().encodeToString(mfm.getFileBytes(StandardLocation.CLASS_OUTPUT, "test.Generated2"));
+                }
+                List<String> options = List.of("-sourcepath", src.toString(),
+                                               "-processor", "TestFilerAsAService$P",
+                                               "-processorpath", System.getProperty("test.classes"),
+                                               "--module-path", libClasses.toString(),
+                                               "--add-modules", "lib",
+                                               "-d", classes.toString(),
+                                               "-AgeneratedData=" + generatedData);
+                JavacTaskImpl task = (JavacTaskImpl) ToolProvider.getSystemJavaCompiler()
+                        .getTask(null, null, null, options, null, sjfm.getJavaFileObjects(tb.findJavaFiles(src)));
+
+                TestJavacFiler.preRegister(task.getContext(), testOutput);
+                task.call();
+
+                List<String> expectedOriginatingFiles = List.of("t.T1", "java.lang.String", "p", "lib1", "lib2", "m", "java.base",
+                                                                "t.T2", "java.lang.CharSequence", "p", "lib1", "lib2", "m", "java.base",
+                                                                "t.T3", "java.lang.Exception", "p", "lib1", "lib2", "m", "java.base");
+                assertEquals(expectedOriginatingFiles, testOutput);
+            } catch (IOException ex) {
+                throw new IllegalStateException(ex);
+            }
+        }
+    }
+
+    @SupportedAnnotationTypes("*")
+    @SupportedOptions("generatedData")
+    public static class P extends AbstractProcessor {
+        int round;
+        @Override
+        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+            System.err.println("nazdar");
+            if (round++ == 0) {
+                ModuleElement mdl = processingEnv.getElementUtils().getModuleElement("m");
+                ModuleElement java_base = processingEnv.getElementUtils().getModuleElement("java.base");
+                PackageElement pack = processingEnv.getElementUtils().getPackageElement("p");
+                PackageElement lib1Pack = processingEnv.getElementUtils().getPackageElement("lib1");
+                PackageElement lib2Pack = processingEnv.getElementUtils().getPackageElement("lib2");
+                Filer filer = processingEnv.getFiler();
+                try {
+                    filer.createSourceFile("test.Generated1",
+                                           element("t.T1"),
+                                           element("java.lang.String"),
+                                           pack,
+                                           lib1Pack,
+                                           lib2Pack,
+                                           mdl,
+                                           java_base).openOutputStream().close();
+                    try (OutputStream out = filer.createClassFile("test.Generated2",
+                                                                  element("t.T2"),
+                                                                  element("java.lang.CharSequence"),
+                                                                  pack,
+                                                                  lib1Pack,
+                                                                  lib2Pack,
+                                                                  mdl,
+                                                                  java_base).openOutputStream()) {
+                        out.write(Base64.getDecoder().decode(processingEnv.getOptions().get("generatedData")));
+                    }
+                    filer.createResource(StandardLocation.CLASS_OUTPUT,
+                                         "test",
+                                         "Generated3.txt",
+                                         element("t.T3"),
+                                         element("java.lang.Exception"),
+                                         pack,
+                                         lib1Pack,
+                                         lib2Pack,
+                                         mdl,
+                                         java_base).openOutputStream().close();
+                } catch (IOException ex) {
+                    throw new AssertionError(ex);
+                }
+            }
+            return false;
+        }
+
+        private Element element(String type) {
+            return processingEnv.getElementUtils().getTypeElement(type);
+        }
+
+        @Override
+        public SourceVersion getSupportedSourceVersion() {
+            return SourceVersion.latest();
+        }
+    }
+
+    public static class TestJavacFiler extends JavacFiler {
+
+
+        protected static void preRegister(Context context, List<String> log) {
+            context.put(filerKey, (Factory<JavacFiler>) c -> new TestJavacFiler(c, log));
+        }
+
+        private final List<String> log;
+
+        public TestJavacFiler(Context c, List<String> log) {
+            super(c);
+            this.log = log;
+        }
+
+        @Override
+        public JavaFileObject createSourceFile(CharSequence nameAndModule, Element... originatingElements) throws IOException {
+            logOriginatingElements(originatingElements);
+            return super.createSourceFile(nameAndModule, originatingElements);
+        }
+
+        @Override
+        public JavaFileObject createClassFile(CharSequence nameAndModule, Element... originatingElements) throws IOException {
+            logOriginatingElements(originatingElements);
+            return super.createClassFile(nameAndModule, originatingElements);
+        }
+
+        @Override
+        public FileObject createResource(JavaFileManager.Location location, CharSequence moduleAndPkg, CharSequence relativeName, Element... originatingElements) throws IOException {
+            logOriginatingElements(originatingElements);
+            return super.createResource(location, moduleAndPkg, relativeName, originatingElements);
+        }
+
+        private void logOriginatingElements(Element[] originatingElements) {
+            Arrays.stream(originatingElements)
+                    .map(e -> e.toString())
+                    .forEach(log::add);
+        }
+
+    }
+    private void assertEquals(Object expected, Object actual) throws AssertionError {
+        if (!expected.equals(actual)) {
+            throw new AssertionError("Unexpected  output: " + actual + ", expected: " + expected);
+        }
+    }
+
+}