diff a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
@@ -35,13 +35,15 @@
 import com.sun.source.tree.CaseTree;
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.source.tree.ModuleTree.ModuleKind;
 
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Flags.Flag;
 import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.file.PathFileObject;
 import com.sun.tools.javac.parser.Tokens.*;
+import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -49,18 +51,20 @@
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
 import com.sun.tools.javac.util.JCDiagnostic.Error;
 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
 import com.sun.tools.javac.util.List;
 
+import static com.sun.tools.javac.code.Flags.asFlagSet;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.*;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.ASSERT;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.CASE;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.CATCH;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.EQ;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.GT;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.LT;
+import static com.sun.tools.javac.parser.Tokens.TokenKind.SYNCHRONIZED;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.ImplicitAndExplicitNotAllowed;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndExplicitNotAllowed;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndImplicitNotAllowed;
 import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
@@ -189,10 +193,12 @@
         this.errorTree = F.Erroneous();
         this.endPosTable = newEndPosTable(keepEndPositions);
         this.allowYieldStatement = Feature.SWITCH_EXPRESSION.allowedInSource(source);
         this.allowRecords = Feature.RECORDS.allowedInSource(source);
         this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
+        this.allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
+                Feature.VALUE_CLASSES.allowedInSource(source);
     }
 
     /** Construct a parser from an existing parser, with minimal overhead.
      */
     @SuppressWarnings("this-escape")
@@ -212,10 +218,12 @@
         this.errorTree = F.Erroneous();
         this.endPosTable = newEndPosTable(false);
         this.allowYieldStatement = Feature.SWITCH_EXPRESSION.allowedInSource(source);
         this.allowRecords = Feature.RECORDS.allowedInSource(source);
         this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
+        this.allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
+                Feature.VALUE_CLASSES.allowedInSource(source);
     }
 
     protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
         return  keepEndPositions
                 ? new SimpleEndPosTable(this)
@@ -249,10 +257,14 @@
 
     /** Switch: are records allowed in this source level?
      */
     boolean allowRecords;
 
+    /** Switch: are value classes allowed in this source level?
+     */
+    boolean allowValueClasses;
+
     /** Switch: are sealed types allowed in this source level?
      */
     boolean allowSealedTypes;
 
     /** The type of the method receiver, as specified by a first "this" parameter.
@@ -1594,12 +1606,12 @@
                             // Don't return here -- error recovery attempt
                             illegal(annos.head.pos);
                         }
                         break loop;
                     case LT:
-                        if (!isMode(TYPE) && isUnboundMemberRef()) {
-                            //this is an unbound method reference whose qualifier
+                        if (!isMode(TYPE) && isParameterizedTypePrefix()) {
+                            //this is either an unbound method reference whose qualifier
                             //is a generic type i.e. A<S>::m
                             int pos1 = token.pos;
                             accept(LT);
                             ListBuffer<JCExpression> args = new ListBuffer<>();
                             args.append(typeArgument());
@@ -1843,11 +1855,11 @@
      * If we see an identifier followed by a '&lt;' it could be an unbound
      * method reference or a binary expression. To disambiguate, look for a
      * matching '&gt;' and see if the subsequent terminal is either '.' or '::'.
      */
     @SuppressWarnings("fallthrough")
-    boolean isUnboundMemberRef() {
+    boolean isParameterizedTypePrefix() {
         int pos = 0, depth = 0;
         outer: for (Token t = S.token(pos) ; ; t = S.token(++pos)) {
             switch (t.kind) {
                 case IDENTIFIER: case UNDERSCORE: case QUES: case EXTENDS: case SUPER:
                 case DOT: case RBRACKET: case LBRACKET: case COMMA:
@@ -2512,15 +2524,18 @@
     }
 
     /** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
      */
     JCExpression creator(int newpos, List<JCExpression> typeArgs) {
-        List<JCAnnotation> newAnnotations = typeAnnotationsOpt();
-
+        final JCModifiers mods = modifiersOpt();
+        List<JCAnnotation> newAnnotations = mods.annotations;
         switch (token.kind) {
         case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
         case DOUBLE: case BOOLEAN:
+            if (mods.flags != 0) {
+                log.error(token.pos, Errors.ModNotAllowedHere(asFlagSet(mods.flags)));
+            }
             if (typeArgs == null) {
                 if (newAnnotations.isEmpty()) {
                     return arrayCreatorRest(newpos, basicType());
                 } else {
                     return arrayCreatorRest(newpos, toP(F.at(newAnnotations.head.pos).AnnotatedType(newAnnotations, basicType())));
@@ -2589,11 +2604,15 @@
         } else if (token.kind == LPAREN) {
             // handle type annotations for instantiations and anonymous classes
             if (newAnnotations.nonEmpty()) {
                 t = insertAnnotationsToMostInner(t, newAnnotations, false);
             }
-            return classCreatorRest(newpos, null, typeArgs, t);
+            JCNewClass newClass = classCreatorRest(newpos, null, typeArgs, t, mods.flags);
+            if ((newClass.def == null) && (mods.flags != 0)) {
+                log.error(newClass.pos, Errors.ModNotAllowedHere(asFlagSet(mods.flags)));
+            }
+            return newClass;
         } else {
             setErrorEndPos(token.pos);
             reportSyntaxError(token.pos, Errors.Expected2(LPAREN, LBRACKET));
             t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.nil(), null));
             return toP(F.at(newpos).Erroneous(List.<JCTree>of(t)));
@@ -2614,11 +2633,11 @@
         if (token.kind == LT) {
             int prevmode = mode;
             t = typeArguments(t, true);
             setMode(prevmode);
         }
-        return classCreatorRest(newpos, encl, typeArgs, t);
+        return classCreatorRest(newpos, encl, typeArgs, t, 0);
     }
 
     /** ArrayCreatorRest = [Annotations] "[" ( "]" BracketsOpt ArrayInitializer
      *                         | Expression "]" {[Annotations]  "[" Expression "]"} BracketsOpt )
      */
@@ -2692,18 +2711,19 @@
     /** ClassCreatorRest = Arguments [ClassBody]
      */
     JCNewClass classCreatorRest(int newpos,
                                   JCExpression encl,
                                   List<JCExpression> typeArgs,
-                                  JCExpression t)
+                                  JCExpression t,
+                                  long flags)
     {
         List<JCExpression> args = arguments();
         JCClassDecl body = null;
         if (token.kind == LBRACE) {
             int pos = token.pos;
             List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
-            JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
+            JCModifiers mods = F.at(Position.NOPOS).Modifiers(flags);
             body = toP(F.at(pos).AnonymousClassDef(mods, defs));
         }
         return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
     }
 
@@ -2934,10 +2954,15 @@
                     nextToken();
                     return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.docComment()));
                 }
             }
         }
+        if ((isValueModifier()) && allowValueClasses) {
+            checkSourceLevel(Feature.VALUE_CLASSES);
+            dc = token.docComment();
+            return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+        }
         if (isRecordStart() && allowRecords) {
             dc = token.docComment();
             return List.of(recordDeclaration(F.at(pos).Modifiers(0), dc));
         } else {
             Token prevToken = token;
@@ -3429,11 +3454,14 @@
         if (token.kind == FINAL || token.kind == MONKEYS_AT) {
             return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
         } else {
             JCExpression t = term(EXPR | TYPE);
             if (wasTypeMode() && LAX_IDENTIFIER.test(token.kind)) {
-                return variableDeclarators(modifiersOpt(), t, stats, true).toList();
+                pos = token.pos;
+                JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
+                F.at(pos);
+                return variableDeclarators(mods, t, stats, true).toList();
             } else if (wasTypeMode() && token.kind == COLON) {
                 log.error(DiagnosticFlag.SYNTAX, pos, Errors.BadInitializer("for-loop"));
                 return List.of((JCStatement)F.at(pos).VarDef(modifiersOpt(), names.error, t, null));
             } else {
                 return moreStatementExpressions(pos, t, stats).toList();
@@ -3526,10 +3554,15 @@
                 if (isSealedClassStart(false)) {
                     checkSourceLevel(Feature.SEALED_CLASSES);
                     flag = Flags.SEALED;
                     break;
                 }
+                if (isValueModifier()) {
+                    checkSourceLevel(Feature.VALUE_CLASSES);
+                    flag = Flags.VALUE_CLASS;
+                    break;
+                }
                 break loop;
             }
             default: break loop;
             }
             if ((flags & flag) != 0) log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.RepeatedModifier);
@@ -3792,10 +3825,17 @@
                 return Source.JDK14;
             } else if (shouldWarn) {
                 log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14));
             }
         }
+        if (name == names.value) {
+            if (allowValueClasses) {
+                return Source.JDK23;
+            } else if (shouldWarn) {
+                log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK23));
+            }
+        }
         if (name == names.sealed) {
             if (allowSealedTypes) {
                 return Source.JDK15;
             } else if (shouldWarn) {
                 log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
@@ -4858,10 +4898,36 @@
             }
         }
         return false;
     }
 
+    protected boolean isValueModifier() {
+        if (token.kind == IDENTIFIER && token.name() == names.value) {
+            boolean isValueModifier = false;
+            Token next = S.token(1);
+            switch (next.kind) {
+                case PRIVATE: case PROTECTED: case PUBLIC: case STATIC: case TRANSIENT:
+                case FINAL: case ABSTRACT: case NATIVE: case VOLATILE: case SYNCHRONIZED:
+                case STRICTFP: case MONKEYS_AT: case DEFAULT: case BYTE: case SHORT:
+                case CHAR: case INT: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
+                case CLASS: case INTERFACE: case ENUM:
+                    isValueModifier = true;
+                    break;
+                case IDENTIFIER: // value record R || value value || new value Comparable() {} ??
+                    if (next.name() == names.record || next.name() == names.value
+                            || (mode & EXPR) != 0)
+                        isValueModifier = true;
+                    break;
+            }
+            if (isValueModifier) {
+                checkSourceLevel(Feature.VALUE_CLASSES);
+                return true;
+            }
+        }
+        return false;
+    }
+
     protected boolean isSealedClassStart(boolean local) {
         if (token.name() == names.sealed) {
             Token next = S.token(1);
             if (allowedAfterSealedOrNonSealed(next, local, false)) {
                 checkSourceLevel(Feature.SEALED_CLASSES);
@@ -4885,11 +4951,13 @@
                 case MONKEYS_AT -> {
                     Token afterNext = S.token(2);
                     yield afterNext.kind != INTERFACE || currentIsNonSealed;
                 }
                 case PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, FINAL, STRICTFP, CLASS, INTERFACE, ENUM -> true;
-                case IDENTIFIER -> isNonSealedIdentifier(next, currentIsNonSealed ? 3 : 1) || next.name() == names.sealed;
+                case IDENTIFIER -> isNonSealedIdentifier(next, currentIsNonSealed ? 3 : 1) ||
+                        next.name() == names.sealed ||
+                        allowValueClasses && next.name() == names.value;
                 default -> false;
             };
     }
 
     /** MethodDeclaratorRest =
