diff a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
@@ -105,10 +105,11 @@
     private final boolean disableProtectedAccessors; // experimental
     private final PkgInfo pkginfoOpt;
     private final boolean optimizeOuterThis;
     private final boolean useMatchException;
     private final HashMap<TypePairs, String> typePairToName;
+    private final boolean allowValueClasses;
     private int variableIndex = 0;
 
     @SuppressWarnings("this-escape")
     protected Lower(Context context) {
         context.put(lowerKey, this);
@@ -138,10 +139,12 @@
         Source source = Source.instance(context);
         Preview preview = Preview.instance(context);
         useMatchException = Feature.PATTERN_SWITCH.allowedInSource(source) &&
                             (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH));
         typePairToName = TypePairs.initialize(syms);
+        this.allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
+                Feature.VALUE_CLASSES.allowedInSource(source);
     }
 
     /** The currently enclosing class.
      */
     ClassSymbol currentClass;
@@ -194,10 +197,14 @@
 
     /** The currently enclosing outermost member definition.
      */
     JCTree outermostMemberDef;
 
+    /** A hash table mapping local classes to a set of outer this fields
+     */
+    public Map<ClassSymbol, Set<JCExpression>> initializerOuterThis = new WeakHashMap<>();
+
     /** A navigator class for assembling a mapping from local class symbols
      *  to class definition trees.
      *  There is only one case; all other cases simply traverse down the tree.
      */
     class ClassMap extends TreeScanner {
@@ -772,11 +779,12 @@
         for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
             ClassSymbol c = l.head;
             if (isTranslatedClassAvailable(c))
                 continue;
             // Create class definition tree.
-            JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
+            // IDENTITY_TYPE will be interpreted as ACC_SUPER for older class files so we are fine
+            JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE,
                     c.outermostClass(), c.flatname, false);
             swapAccessConstructorTag(c, cdec.sym);
             translated.append(cdec);
         }
     }
@@ -1244,11 +1252,12 @@
             Name flatname = names.fromString("" + topClass.getQualifiedName() +
                                             target.syntheticNameChar() +
                                             i);
             ClassSymbol ctag = chk.getCompiled(topModle, flatname);
             if (ctag == null)
-                ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
+                // IDENTITY_TYPE will be interpreted as ACC_SUPER for older class files so we are fine
+                ctag = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, topClass).sym;
             else if (!ctag.isAnonymous())
                 continue;
             // keep a record of all tags, to verify that all are generated as required
             accessConstrTags = accessConstrTags.prepend(ctag);
             return ctag;
@@ -1400,13 +1409,14 @@
         }
         return proxyName;
     }
 
     /** Proxy definitions for all free variables in given list, in reverse order.
-     *  @param pos        The source code position of the definition.
-     *  @param freevars   The free variables.
-     *  @param owner      The class in which the definitions go.
+     *  @param pos               The source code position of the definition.
+     *  @param freevars          The free variables.
+     *  @param owner             The class in which the definitions go.
+     *  @param additionalFlags   Any additional flags
      */
     List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
         return freevarDefs(pos, freevars, owner, LOCAL_CAPTURE_FIELD);
     }
 
@@ -1493,11 +1503,11 @@
     /** Definition for this$n field.
      *  @param pos        The source code position of the definition.
      *  @param owner      The class in which the definition goes.
      */
     JCVariableDecl outerThisDef(int pos, ClassSymbol owner) {
-        VarSymbol outerThis = makeOuterThisVarSymbol(owner, FINAL | SYNTHETIC);
+        VarSymbol outerThis = makeOuterThisVarSymbol(owner, FINAL | SYNTHETIC | (allowValueClasses && owner.isValueClass() ? STRICT : 0));
         return makeOuterThisVarDecl(pos, outerThis);
     }
 
     /** Return a list of trees that load the free variables in given list,
      *  in reverse order.
@@ -1824,11 +1834,12 @@
         Scope s = clazz.members();
         for (Symbol sym : s.getSymbols(NON_RECURSIVE))
             if (sym.kind == TYP &&
                 sym.name == names.empty &&
                 (sym.flags() & INTERFACE) == 0) return (ClassSymbol) sym;
-        return makeEmptyClass(STATIC | SYNTHETIC, clazz).sym;
+        // IDENTITY_TYPE will be interpreted as ACC_SUPER for older class files so we are fine
+        return makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, clazz).sym;
     }
 
     /** Create an attributed tree of the form left.name(). */
     private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
         Assert.checkNonNull(left.type);
@@ -1876,11 +1887,12 @@
     /**Used to create an auxiliary class to hold $assertionsDisabled for interfaces.
      */
     private ClassSymbol assertionsDisabledClass() {
         if (assertionsDisabledClassCache != null) return assertionsDisabledClassCache;
 
-        assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC, outermostClassDef.sym).sym;
+        // IDENTITY_TYPE will be interpreted as ACC_SUPER for older class files so we are fine
+        assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, outermostClassDef.sym).sym;
 
         return assertionsDisabledClassCache;
     }
 
     // This code is not particularly robust if the user has
@@ -2164,11 +2176,11 @@
         if (currentClass.hasOuterInstance())
             otdef = outerThisDef(tree.pos, currentClass);
 
         // If this is a local class, define proxies for all its free variables.
         List<JCVariableDecl> fvdefs = freevarDefs(
-            tree.pos, freevars(currentClass), currentClass);
+            tree.pos, freevars(currentClass), currentClass, allowValueClasses && currentClass.isValueClass() ? STRICT : LOCAL_CAPTURE_FIELD);
 
         // Recursively translate superclass, interfaces.
         tree.extending = translate(tree.extending);
         tree.implementing = translate(tree.implementing);
 
@@ -2738,23 +2750,29 @@
             ListBuffer<VarSymbol> fields = new ListBuffer<>();
             for (Symbol sym : currentClass.getEnclosedElements()) {
                 if (sym.kind == Kinds.Kind.VAR && ((sym.flags() & RECORD) != 0))
                     fields.append((VarSymbol) sym);
             }
+            ListBuffer<JCStatement> initializers = new ListBuffer<>();
             for (VarSymbol field: fields) {
                 if ((field.flags_field & Flags.UNINITIALIZED_FIELD) != 0) {
                     VarSymbol param = tree.params.stream().filter(p -> p.name == field.name).findFirst().get().sym;
                     make.at(tree.pos);
-                    tree.body.stats = tree.body.stats.append(
-                            make.Exec(
-                                    make.Assign(
-                                            make.Select(make.This(field.owner.erasure(types)), field),
-                                            make.Ident(param)).setType(field.erasure(types))));
-                    // we don't need the flag at the field anymore
+                    initializers.add(make.Exec(
+                            make.Assign(
+                                    make.Select(make.This(field.owner.erasure(types)), field),
+                                    make.Ident(param)).setType(field.erasure(types))));
                     field.flags_field &= ~Flags.UNINITIALIZED_FIELD;
                 }
             }
+            if (initializers.nonEmpty()) {
+                if (tree.sym.owner.isValueClass()) {
+                    TreeInfo.mapSuperCalls(tree.body, supercall -> make.Block(0, initializers.toList().append(supercall)));
+                } else {
+                    tree.body.stats = tree.body.stats.appendList(initializers);
+                }
+            }
         }
         result = tree;
     }
 
     public void visitTypeCast(JCTypeCast tree) {
@@ -2966,10 +2984,21 @@
                 // local class
                 thisArg = makeThis(tree.pos(), c.innermostAccessibleEnclosingClass());
             } else {
                 // nested class
                 thisArg = makeOwnerThis(tree.pos(), c, false);
+                if (currentMethodSym != null &&
+                        ((currentMethodSym.flags_field & (STATIC | BLOCK)) == BLOCK) &&
+                        currentMethodSym.owner.isValueClass()) {
+                    // instance initializer in a value class
+                    Set<JCExpression> outerThisSet = initializerOuterThis.get(currentClass);
+                    if (outerThisSet == null) {
+                        outerThisSet = new HashSet<>();
+                    }
+                    outerThisSet.add(thisArg);
+                    initializerOuterThis.put(currentClass, outerThisSet);
+                }
             }
             tree.args = tree.args.prepend(thisArg);
         }
         tree.encl = null;
 
