KT-4107 Data objects
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt
index 5c95698..43a879a 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt
@@ -2438,6 +2438,12 @@
             token,
         )
     }
+    add(FirErrors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE) { firDiagnostic ->
+        DataObjectCustomEqualsOrHashCodeImpl(
+            firDiagnostic as KtPsiDiagnostic,
+            token,
+        )
+    }
     add(FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE) { firDiagnostic ->
         FunInterfaceConstructorReferenceImpl(
             firDiagnostic as KtPsiDiagnostic,
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt
index ce18175..012ba58 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt
@@ -1729,6 +1729,10 @@
         override val diagnosticClass get() = TailRecursionInTryIsNotSupported::class
     }
 
+    abstract class DataObjectCustomEqualsOrHashCode : KtFirDiagnostic<KtNamedFunction>() {
+        override val diagnosticClass get() = DataObjectCustomEqualsOrHashCode::class
+    }
+
     abstract class FunInterfaceConstructorReference : KtFirDiagnostic<KtExpression>() {
         override val diagnosticClass get() = FunInterfaceConstructorReference::class
     }
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt
index 8a3e8c1..788c975 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt
@@ -2073,6 +2073,11 @@
     override val token: KtLifetimeToken,
 ) : KtFirDiagnostic.TailRecursionInTryIsNotSupported(), KtAbstractFirDiagnostic<PsiElement>
 
+internal class DataObjectCustomEqualsOrHashCodeImpl(
+    override val firDiagnostic: KtPsiDiagnostic,
+    override val token: KtLifetimeToken,
+) : KtFirDiagnostic.DataObjectCustomEqualsOrHashCode(), KtAbstractFirDiagnostic<KtNamedFunction>
+
 internal class FunInterfaceConstructorReferenceImpl(
     override val firDiagnostic: KtPsiDiagnostic,
     override val token: KtLifetimeToken,
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java
index 49a09de..d2f5011 100644
--- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java
+++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java
@@ -6957,6 +6957,12 @@
             }
 
             @Test
+            @TestMetadata("companionDataObject.kt")
+            public void testCompanionDataObject() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt");
+            }
+
+            @Test
             @TestMetadata("componentNamedComponent1.kt")
             public void testComponentNamedComponent1() throws Exception {
                 runTest("compiler/testData/diagnostics/tests/dataClasses/componentNamedComponent1.kt");
@@ -7029,9 +7035,21 @@
             }
 
             @Test
-            @TestMetadata("dataObject.kt")
-            public void testDataObject() throws Exception {
-                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObject.kt");
+            @TestMetadata("dataObjectDisabled.kt")
+            public void testDataObjectDisabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt");
+            }
+
+            @Test
+            @TestMetadata("dataObjectEnabled.kt")
+            public void testDataObjectEnabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt");
+            }
+
+            @Test
+            @TestMetadata("dataObjectLiteral.kt")
+            public void testDataObjectLiteral() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt");
             }
 
             @Test
@@ -7656,6 +7674,22 @@
         }
 
         @Nested
+        @TestMetadata("compiler/testData/diagnostics/tests/dataObjects")
+        @TestDataPath("$PROJECT_ROOT")
+        public class DataObjects {
+            @Test
+            public void testAllFilesPresentInDataObjects() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataObjects"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
+            }
+
+            @Test
+            @TestMetadata("overrideEqualsAndHashCode.kt")
+            public void testOverrideEqualsAndHashCode() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt");
+            }
+        }
+
+        @Nested
         @TestMetadata("compiler/testData/diagnostics/tests/declarationChecks")
         @TestDataPath("$PROJECT_ROOT")
         public class DeclarationChecks {
diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/DataClassMethodGenerator.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/DataClassMethodGenerator.kt
index 1eec756..a22905c 100644
--- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/DataClassMethodGenerator.kt
+++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/DataClassMethodGenerator.kt
@@ -19,6 +19,7 @@
 import org.jetbrains.kotlin.descriptors.FunctionDescriptor
 import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
 import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtObjectDeclaration
 import org.jetbrains.kotlin.psi.KtParameter
 import org.jetbrains.kotlin.resolve.BindingContext
 
@@ -33,8 +34,10 @@
 ) : FunctionsFromAnyGenerator(declaration, bindingContext) {
 
     override fun generate() {
-        generateComponentFunctionsForDataClasses()
-        generateCopyFunctionForDataClasses(primaryConstructorParameters)
+        if (declaration !is KtObjectDeclaration) {
+            generateComponentFunctionsForDataClasses()
+            generateCopyFunctionForDataClasses(primaryConstructorParameters)
+        }
 
         super.generate()
     }
diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt
index 577314e..67f0498 100644
--- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt
+++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt
@@ -21,11 +21,9 @@
 
     open fun generate() {
         val properties = primaryConstructorProperties
-        if (properties.isNotEmpty()) {
-            generateToStringIfNeeded(properties)
-            generateHashCodeIfNeeded(properties)
-            generateEqualsIfNeeded(properties)
-        }
+        generateToStringIfNeeded(properties)
+        generateHashCodeIfNeeded(properties)
+        generateEqualsIfNeeded(properties)
     }
 
     protected abstract fun generateToStringMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>)
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java
index dd86b2f..a8a9d45 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java
@@ -17,8 +17,10 @@
 import org.jetbrains.kotlin.descriptors.ClassDescriptor;
 import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
 import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
+import org.jetbrains.kotlin.name.FqName;
 import org.jetbrains.kotlin.psi.KtClassOrObject;
 import org.jetbrains.kotlin.resolve.BindingContext;
+import org.jetbrains.kotlin.resolve.DescriptorUtils;
 import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
@@ -103,42 +105,46 @@
 
         mv.visitCode();
 
-        StringConcatGenerator generator = StringConcatGenerator.Companion.create(generationState, iv);
-        generator.genStringBuilderConstructorIfNeded();
-        boolean first = true;
+        if (properties.isEmpty()) {
+            iv.aconst(classDescriptor.getName().asString());
+        } else {
+            StringConcatGenerator generator = StringConcatGenerator.Companion.create(generationState, iv);
+            generator.genStringBuilderConstructorIfNeded();
+            boolean first = true;
 
-        for (PropertyDescriptor propertyDescriptor : properties) {
-            if (first) {
-                generator.addStringConstant(classDescriptor.getName() + "(" + propertyDescriptor.getName().asString() + "=");
-                first = false;
-            }
-            else {
-                generator.addStringConstant(", " + propertyDescriptor.getName().asString() + "=");
-            }
-
-            JvmKotlinType type = genOrLoadOnStack(iv, context, propertyDescriptor, 0);
-            Type asmType = type.getType();
-            KotlinType kotlinType = type.getKotlinType();
-
-            if (asmType.getSort() == Type.ARRAY) {
-                Type elementType = correctElementType(asmType);
-                if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
-                    iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;", false);
-                    asmType = JAVA_STRING_TYPE;
-                    kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType();
+            for (PropertyDescriptor propertyDescriptor : properties) {
+                if (first) {
+                    generator.addStringConstant(classDescriptor.getName() + "(" + propertyDescriptor.getName().asString() + "=");
+                    first = false;
                 }
-                else if (elementType.getSort() != Type.CHAR) {
-                    iv.invokestatic("java/util/Arrays", "toString", "(" + asmType.getDescriptor() + ")Ljava/lang/String;", false);
-                    asmType = JAVA_STRING_TYPE;
-                    kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType();
+                else {
+                    generator.addStringConstant(", " + propertyDescriptor.getName().asString() + "=");
                 }
+
+                JvmKotlinType type = genOrLoadOnStack(iv, context, propertyDescriptor, 0);
+                Type asmType = type.getType();
+                KotlinType kotlinType = type.getKotlinType();
+
+                if (asmType.getSort() == Type.ARRAY) {
+                    Type elementType = correctElementType(asmType);
+                    if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
+                        iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;", false);
+                        asmType = JAVA_STRING_TYPE;
+                        kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType();
+                    }
+                    else if (elementType.getSort() != Type.CHAR) {
+                        iv.invokestatic("java/util/Arrays", "toString", "(" + asmType.getDescriptor() + ")Ljava/lang/String;", false);
+                        asmType = JAVA_STRING_TYPE;
+                        kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType();
+                    }
+                }
+                genInvokeAppendMethod(generator, asmType, kotlinType, typeMapper, StackValue.onStack(asmType));
             }
-            genInvokeAppendMethod(generator, asmType, kotlinType, typeMapper, StackValue.onStack(asmType));
+
+            generator.addStringConstant(")");
+
+            generator.genToString();
         }
-
-        generator.addStringConstant(")");
-
-        generator.genToString();
         iv.areturn(JAVA_STRING_TYPE);
 
         FunctionCodegen.endVisit(mv, toStringMethodName, getDeclaration());
@@ -175,41 +181,45 @@
         InstructionAdapter iv = new InstructionAdapter(mv);
 
         mv.visitCode();
-        boolean first = true;
-        for (PropertyDescriptor propertyDescriptor : properties) {
-            if (!first) {
-                iv.iconst(31);
-                iv.mul(Type.INT_TYPE);
-            }
+        if (properties.isEmpty()) {
+            iv.iconst(DescriptorUtils.getFqNameSafe(classDescriptor).asString().hashCode());
+        } else {
+            boolean first = true;
+            for (PropertyDescriptor propertyDescriptor : properties) {
+                if (!first) {
+                    iv.iconst(31);
+                    iv.mul(Type.INT_TYPE);
+                }
 
-            JvmKotlinType propertyType = genOrLoadOnStack(iv, context, propertyDescriptor, 0);
-            KotlinType kotlinType = propertyDescriptor.getReturnType();
-            Type asmType = typeMapper.mapType(kotlinType);
-            StackValue.coerce(propertyType.getType(), propertyType.getKotlinType(), asmType, kotlinType, iv);
+                JvmKotlinType propertyType = genOrLoadOnStack(iv, context, propertyDescriptor, 0);
+                KotlinType kotlinType = propertyDescriptor.getReturnType();
+                Type asmType = typeMapper.mapType(kotlinType);
+                StackValue.coerce(propertyType.getType(), propertyType.getKotlinType(), asmType, kotlinType, iv);
 
-            Label ifNull = null;
-            if (!isPrimitive(asmType)) {
-                ifNull = new Label();
-                iv.dup();
-                iv.ifnull(ifNull);
-            }
+                Label ifNull = null;
+                if (!isPrimitive(asmType)) {
+                    ifNull = new Label();
+                    iv.dup();
+                    iv.ifnull(ifNull);
+                }
 
-            genHashCode(mv, iv, asmType, generationState.getTarget());
+                genHashCode(mv, iv, asmType, generationState.getTarget());
 
-            if (ifNull != null) {
-                Label end = new Label();
-                iv.goTo(end);
-                iv.mark(ifNull);
-                iv.pop();
-                iv.iconst(0);
-                iv.mark(end);
-            }
+                if (ifNull != null) {
+                    Label end = new Label();
+                    iv.goTo(end);
+                    iv.mark(ifNull);
+                    iv.pop();
+                    iv.iconst(0);
+                    iv.mark(end);
+                }
 
-            if (first) {
-                first = false;
-            }
-            else {
-                iv.add(Type.INT_TYPE);
+                if (first) {
+                    first = false;
+                }
+                else {
+                    iv.add(Type.INT_TYPE);
+                }
             }
         }
 
diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java
index 1afd739..f90e2d1 100644
--- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java
+++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java
@@ -6957,6 +6957,12 @@
             }
 
             @Test
+            @TestMetadata("companionDataObject.kt")
+            public void testCompanionDataObject() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt");
+            }
+
+            @Test
             @TestMetadata("componentNamedComponent1.kt")
             public void testComponentNamedComponent1() throws Exception {
                 runTest("compiler/testData/diagnostics/tests/dataClasses/componentNamedComponent1.kt");
@@ -7029,9 +7035,21 @@
             }
 
             @Test
-            @TestMetadata("dataObject.kt")
-            public void testDataObject() throws Exception {
-                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObject.kt");
+            @TestMetadata("dataObjectDisabled.kt")
+            public void testDataObjectDisabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt");
+            }
+
+            @Test
+            @TestMetadata("dataObjectEnabled.kt")
+            public void testDataObjectEnabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt");
+            }
+
+            @Test
+            @TestMetadata("dataObjectLiteral.kt")
+            public void testDataObjectLiteral() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt");
             }
 
             @Test
@@ -7656,6 +7674,22 @@
         }
 
         @Nested
+        @TestMetadata("compiler/testData/diagnostics/tests/dataObjects")
+        @TestDataPath("$PROJECT_ROOT")
+        public class DataObjects {
+            @Test
+            public void testAllFilesPresentInDataObjects() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataObjects"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
+            }
+
+            @Test
+            @TestMetadata("overrideEqualsAndHashCode.kt")
+            public void testOverrideEqualsAndHashCode() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt");
+            }
+        }
+
+        @Nested
         @TestMetadata("compiler/testData/diagnostics/tests/declarationChecks")
         @TestDataPath("$PROJECT_ROOT")
         public class DeclarationChecks {
diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java
index 600cb95..2839427 100644
--- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java
+++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java
@@ -6957,6 +6957,12 @@
             }
 
             @Test
+            @TestMetadata("companionDataObject.kt")
+            public void testCompanionDataObject() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt");
+            }
+
+            @Test
             @TestMetadata("componentNamedComponent1.kt")
             public void testComponentNamedComponent1() throws Exception {
                 runTest("compiler/testData/diagnostics/tests/dataClasses/componentNamedComponent1.kt");
@@ -7029,9 +7035,21 @@
             }
 
             @Test
-            @TestMetadata("dataObject.kt")
-            public void testDataObject() throws Exception {
-                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObject.kt");
+            @TestMetadata("dataObjectDisabled.kt")
+            public void testDataObjectDisabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt");
+            }
+
+            @Test
+            @TestMetadata("dataObjectEnabled.kt")
+            public void testDataObjectEnabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt");
+            }
+
+            @Test
+            @TestMetadata("dataObjectLiteral.kt")
+            public void testDataObjectLiteral() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt");
             }
 
             @Test
@@ -7656,6 +7674,22 @@
         }
 
         @Nested
+        @TestMetadata("compiler/testData/diagnostics/tests/dataObjects")
+        @TestDataPath("$PROJECT_ROOT")
+        public class DataObjects {
+            @Test
+            public void testAllFilesPresentInDataObjects() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataObjects"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
+            }
+
+            @Test
+            @TestMetadata("overrideEqualsAndHashCode.kt")
+            public void testOverrideEqualsAndHashCode() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt");
+            }
+        }
+
+        @Nested
         @TestMetadata("compiler/testData/diagnostics/tests/declarationChecks")
         @TestDataPath("$PROJECT_ROOT")
         public class DeclarationChecks {
diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt
index a442590..59bd1a5 100644
--- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt
+++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt
@@ -16,6 +16,7 @@
 import org.jetbrains.kotlin.descriptors.Visibility
 import org.jetbrains.kotlin.diagnostics.WhenMissingCase
 import org.jetbrains.kotlin.diagnostics.deprecationError2
+import org.jetbrains.kotlin.diagnostics.error0
 import org.jetbrains.kotlin.fir.FirModuleData
 import org.jetbrains.kotlin.fir.PrivateForInline
 import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
@@ -901,6 +902,7 @@
         val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error<KtNamedFunction>(PositioningStrategy.TAILREC_MODIFIER)
         val NON_TAIL_RECURSIVE_CALL by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
         val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
+        val DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE by error<KtNamedFunction>(PositioningStrategy.OVERRIDE_MODIFIER)
     }
 
     val FUN_INTERFACES by object : DiagnosticGroup("Fun interfaces") {
diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt
index a221de1..db0c832 100644
--- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt
+++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt
@@ -483,6 +483,7 @@
     val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error0<KtNamedFunction>(SourceElementPositioningStrategies.TAILREC_MODIFIER)
     val NON_TAIL_RECURSIVE_CALL by warning0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
     val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
+    val DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE by error0<KtNamedFunction>(SourceElementPositioningStrategies.OVERRIDE_MODIFIER)
 
     // Fun interfaces
     val FUN_INTERFACE_CONSTRUCTOR_REFERENCE by error0<KtExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt
index 561e5f3..5344e26 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt
@@ -54,6 +54,7 @@
             FirTailrecFunctionChecker,
             FirTopLevelFunctionsChecker,
             FirMemberFunctionsChecker,
+            FirDataObjectContentChecker,
         )
 
     override val propertyCheckers: Set<FirPropertyChecker>
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDataObjectContentChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDataObjectContentChecker.kt
new file mode 100644
index 0000000..13e23c2
--- /dev/null
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDataObjectContentChecker.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.analysis.checkers.declaration
+
+import org.jetbrains.kotlin.KtFakeSourceElementKind
+import org.jetbrains.kotlin.descriptors.ClassKind
+import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
+import org.jetbrains.kotlin.diagnostics.reportOn
+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
+import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
+import org.jetbrains.kotlin.fir.declarations.FirClass
+import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
+import org.jetbrains.kotlin.fir.types.isNullableAny
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.util.OperatorNameConventions
+
+object FirDataObjectContentChecker : FirSimpleFunctionChecker() {
+    override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
+        if (!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return
+        val source = declaration.source
+        if (source == null || source.kind is KtFakeSourceElementKind) return
+
+        val containingClass = context.containingDeclarations.lastOrNull() as? FirClass ?: return
+        if (containingClass.classKind != ClassKind.OBJECT || !containingClass.hasModifier(KtTokens.DATA_KEYWORD)) return
+
+        if (
+            (declaration.name == OperatorNameConventions.HASH_CODE && declaration.valueParameters.isEmpty()) ||
+            (declaration.name == OperatorNameConventions.EQUALS &&
+                    declaration.valueParameters.singleOrNull()?.returnTypeRef?.isNullableAny == true)
+        ) {
+            reporter.reportOn(source, FirErrors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE, context)
+        }
+    }
+}
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt
index 6336f08..e0b4850 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt
@@ -7,6 +7,7 @@
 
 import org.jetbrains.kotlin.KtFakeSourceElementKind
 import org.jetbrains.kotlin.KtSourceElement
+import org.jetbrains.kotlin.config.LanguageFeature
 import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
 import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.Companion.classActualTargets
 import org.jetbrains.kotlin.fir.analysis.checkers.FirModifier
@@ -27,6 +28,7 @@
 import org.jetbrains.kotlin.fir.languageVersionSettings
 import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
 import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.lexer.KtTokens.DATA_KEYWORD
 import org.jetbrains.kotlin.resolve.*
 
 object FirModifierChecker : FirBasicDeclarationChecker() {
@@ -182,7 +184,11 @@
             }
             val set = map[modifierToken] ?: emptySet()
             val checkResult = if (factory == FirErrors.WRONG_MODIFIER_TARGET) {
-                actualTargets.none { it in set }
+                actualTargets.none { it in set } ||
+                        // TODO: Implement some generic feature-checking mechanism
+                        (modifierToken == DATA_KEYWORD
+                                && actualTargets.contains(KotlinTarget.STANDALONE_OBJECT)
+                                && !context.languageVersionSettings.supportsFeature(LanguageFeature.DataObjects))
             } else {
                 actualTargets.any { it in set }
             }
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt
index 5d63b7c..c07319a 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt
@@ -136,6 +136,7 @@
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_OVERRIDE_CONFLICT
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_VARARG_PARAMETER
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_WITHOUT_PARAMETERS
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DECLARATION_CANT_BE_INLINED
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATED_PROPERTY_INSIDE_VALUE_CLASS
@@ -579,7 +580,6 @@
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_PARAMETER_TYPE
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_RETURN_TYPE
-import org.jetbrains.kotlin.psi.KtReferenceExpression
 
 @Suppress("unused")
 object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
@@ -1456,6 +1456,7 @@
         map.put(TAILREC_ON_VIRTUAL_MEMBER_ERROR, "Tailrec is not allowed on open members")
         map.put(NON_TAIL_RECURSIVE_CALL, "Recursive call is not a tail call")
         map.put(TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED, "Tail recursion optimization inside try/catch/finally is not supported")
+        map.put(DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE, "Data object cannot have a custom implementation of 'equals' or 'hashCode'")
 
         // Fun interfaces
         map.put(FUN_INTERFACE_CONSTRUCTOR_REFERENCE, "Functional/SAM interface constructor references are prohibited")
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt
index 2c36821..bdd019c 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt
@@ -87,6 +87,7 @@
             IrGeneratorContextBase(components.irBuiltIns),
             components.symbolTable,
             irClass,
+            irClass.kotlinFqName,
             origin
         ) {
             override fun declareSimpleFunction(startOffset: Int, endOffset: Int, functionDescriptor: FunctionDescriptor): IrFunction {
@@ -183,9 +184,6 @@
         fun generate(klass: FirClass): List<FirDeclaration> {
             val propertyParametersCount = irClass.primaryConstructor?.explicitParameters?.size ?: 0
             val properties = irClass.properties.filter { it.backingField != null }.take(propertyParametersCount).toList()
-            if (properties.isEmpty()) {
-                return emptyList()
-            }
 
             val result = mutableListOf<FirDeclaration>()
 
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java
index e4f5d57..c4738d93 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java
@@ -13649,6 +13649,46 @@
     }
 
     @Nested
+    @TestMetadata("compiler/testData/codegen/box/dataObjects")
+    @TestDataPath("$PROJECT_ROOT")
+    public class DataObjects {
+        @Test
+        public void testAllFilesPresentInDataObjects() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+        }
+
+        @Test
+        @TestMetadata("equals.kt")
+        public void testEquals() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/equals.kt");
+        }
+
+        @Test
+        @TestMetadata("hashCode.kt")
+        public void testHashCode() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt");
+        }
+
+        @Test
+        @TestMetadata("multipleInstances.kt")
+        public void testMultipleInstances() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/multipleInstances.kt");
+        }
+
+        @Test
+        @TestMetadata("serialization.kt")
+        public void testSerialization() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/serialization.kt");
+        }
+
+        @Test
+        @TestMetadata("toString.kt")
+        public void testToString() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/toString.kt");
+        }
+    }
+
+    @Nested
     @TestMetadata("compiler/testData/codegen/box/deadCodeElimination")
     @TestDataPath("$PROJECT_ROOT")
     public class DeadCodeElimination {
diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt
index ce0846b..bf2e6bc 100644
--- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt
+++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt
@@ -8,6 +8,7 @@
 import com.intellij.psi.tree.IElementType
 import org.jetbrains.kotlin.*
 import org.jetbrains.kotlin.KtNodeTypes.*
+import org.jetbrains.kotlin.descriptors.ClassKind
 import org.jetbrains.kotlin.descriptors.Modality
 import org.jetbrains.kotlin.descriptors.Visibilities
 import org.jetbrains.kotlin.fir.*
@@ -38,6 +39,7 @@
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.name.SpecialNames
 import org.jetbrains.kotlin.parsing.*
+import org.jetbrains.kotlin.psi.KtObjectDeclaration
 import org.jetbrains.kotlin.psi.KtPsiUtil
 import org.jetbrains.kotlin.types.ConstantValueKind
 import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -1078,8 +1080,10 @@
         private val createParameterTypeRefWithSourceKind: (FirProperty, KtFakeSourceElementKind) -> FirTypeRef,
     ) {
         fun generate() {
-            generateComponentFunctions()
-            generateCopyFunction()
+            if (classBuilder.classKind != ClassKind.OBJECT) {
+                generateComponentFunctions()
+                generateCopyFunction()
+            }
             // Refer to (IR utils or FIR backend) DataClassMembersGenerator for generating equals, hashCode, and toString
         }
 
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
index 50499fd..8700376 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
@@ -737,6 +737,7 @@
     DiagnosticFactory0<PsiElement> DATA_CLASS_WITHOUT_PARAMETERS = DiagnosticFactory0.create(ERROR);
     DiagnosticFactory0<KtParameter> DATA_CLASS_VARARG_PARAMETER = DiagnosticFactory0.create(ERROR);
     DiagnosticFactory0<KtParameter> DATA_CLASS_NOT_PROPERTY_PARAMETER = DiagnosticFactory0.create(ERROR);
+    DiagnosticFactory0<PsiElement> DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE = DiagnosticFactory0.create(ERROR);
 
     DiagnosticFactory0<KtParameter> CATCH_PARAMETER_WITH_DEFAULT_VALUE = DiagnosticFactory0.create(ERROR);
 
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
index 42472a0..364ee63 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
@@ -1058,6 +1058,7 @@
         MAP.put(DATA_CLASS_WITHOUT_PARAMETERS, "Data class must have at least one primary constructor parameter");
         MAP.put(DATA_CLASS_VARARG_PARAMETER, "Primary constructor vararg parameters are forbidden for data classes");
         MAP.put(DATA_CLASS_NOT_PROPERTY_PARAMETER, "Data class primary constructor must only have property (val / var) parameters");
+        MAP.put(DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE, "Data object cannot have a custom implementation of 'equals' or 'hashCode'");
 
         MAP.put(CATCH_PARAMETER_WITH_DEFAULT_VALUE, "Catch clause parameter may not have a default value");
 
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt
index ace2226..c947604 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt
@@ -52,6 +52,7 @@
     ValueParameterUsageInDefaultArgumentChecker,
     CyclicAnnotationsChecker,
     UnsupportedUntilRangeDeclarationChecker,
+    DataObjectContentChecker,
 )
 
 private val DEFAULT_CALL_CHECKERS = listOf(
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataClassDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataClassDeclarationChecker.kt
index 7821464..fe66ec8 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataClassDeclarationChecker.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataClassDeclarationChecker.kt
@@ -17,6 +17,7 @@
 package org.jetbrains.kotlin.resolve.checkers
 
 import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.ClassKind
 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
 import org.jetbrains.kotlin.diagnostics.Errors
 import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -27,7 +28,7 @@
         if (descriptor !is ClassDescriptor) return
         if (declaration !is KtClassOrObject) return
 
-        if (descriptor.isData) {
+        if (descriptor.isData && descriptor.kind == ClassKind.CLASS) {
             if (descriptor.unsubstitutedPrimaryConstructor == null && descriptor.constructors.isNotEmpty()) {
                 declaration.nameIdentifier?.let { context.trace.report(Errors.PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS.on(it)) }
             }
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataObjectContentChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataObjectContentChecker.kt
new file mode 100644
index 0000000..66270fb
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataObjectContentChecker.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.resolve.checkers
+
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.ClassKind
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.diagnostics.Errors
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.resolve.DescriptorUtils
+import org.jetbrains.kotlin.util.OperatorNameConventions
+
+object DataObjectContentChecker : DeclarationChecker {
+    override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
+        if (descriptor !is FunctionDescriptor) return
+        if (descriptor.name != OperatorNameConventions.EQUALS && descriptor.name != OperatorNameConventions.HASH_CODE) return
+
+        val container = descriptor.containingDeclaration
+        if (container !is ClassDescriptor) return
+        if (!container.isData || container.kind != ClassKind.OBJECT) return
+
+        if (DescriptorUtils.getAllOverriddenDescriptors(descriptor).any(::isDeclaredInAny)) {
+            val target = declaration.modifierList?.getModifier(KtTokens.OVERRIDE_KEYWORD) ?: declaration
+            context.trace.report(Errors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE.on(target))
+        }
+    }
+
+    private fun isDeclaredInAny(descriptor: FunctionDescriptor): Boolean {
+        val container = descriptor.containingDeclaration
+        return container is ClassDescriptor && KotlinBuiltIns.isAny(container)
+    }
+}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt
index 1062505..e015771 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt
@@ -482,7 +482,7 @@
     }
 
     private fun addDataClassMethods(result: MutableCollection<DeclarationDescriptor>, location: LookupLocation) {
-        if (!thisDescriptor.isData) return
+        if (!thisDescriptor.isData || thisDescriptor.kind != ClassKind.CLASS) return
 
         if (getPrimaryConstructor() == null) return
 
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/MethodsFromAnyGeneratorForLowerings.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/MethodsFromAnyGeneratorForLowerings.kt
index 839ed89..a783975 100644
--- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/MethodsFromAnyGeneratorForLowerings.kt
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/MethodsFromAnyGeneratorForLowerings.kt
@@ -14,17 +14,13 @@
 import org.jetbrains.kotlin.ir.builders.declarations.addFunction
 import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
 import org.jetbrains.kotlin.ir.declarations.*
-import org.jetbrains.kotlin.ir.expressions.IrExpression
 import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
 import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
 import org.jetbrains.kotlin.ir.types.IrType
 import org.jetbrains.kotlin.ir.types.classOrNull
 import org.jetbrains.kotlin.ir.types.getClass
 import org.jetbrains.kotlin.ir.types.isArray
-import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator
-import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
-import org.jetbrains.kotlin.ir.util.functions
-import org.jetbrains.kotlin.ir.util.isPrimitiveArray
+import org.jetbrains.kotlin.ir.util.*
 
 class MethodsFromAnyGeneratorForLowerings(val context: BackendContext, val irClass: IrClass, val origin: IrDeclarationOrigin) {
     private fun IrClass.addSyntheticFunction(name: String, returnType: IrType) =
@@ -74,6 +70,7 @@
         IrGeneratorContextBase(backendContext.irBuiltIns),
         backendContext.ir.symbols.externalSymbolTable,
         irClass,
+        irClass.kotlinFqName,
         origin,
         forbidDirectFieldAccess
     ) {
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt
index 23cb79c..8356fed 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt
@@ -353,6 +353,7 @@
 
     enumClassPhase,
     objectClassPhase,
+    readResolveForDataObjectsPhase,
     staticInitializersPhase,
     initializersPhase,
     initializersCleanupPhase,
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReadResolveForDataObjectsLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReadResolveForDataObjectsLowering.kt
new file mode 100644
index 0000000..8827f87
--- /dev/null
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReadResolveForDataObjectsLowering.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.backend.jvm.lower
+
+import org.jetbrains.kotlin.backend.common.ClassLoweringPass
+import org.jetbrains.kotlin.backend.common.ir.addDispatchReceiver
+import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
+import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
+import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
+import org.jetbrains.kotlin.config.LanguageFeature
+import org.jetbrains.kotlin.descriptors.ClassKind
+import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
+import org.jetbrains.kotlin.descriptors.Modality
+import org.jetbrains.kotlin.ir.builders.declarations.buildFun
+import org.jetbrains.kotlin.ir.builders.irExprBody
+import org.jetbrains.kotlin.ir.builders.irGetField
+import org.jetbrains.kotlin.ir.declarations.IrClass
+import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
+import org.jetbrains.kotlin.ir.util.defaultType
+import org.jetbrains.kotlin.ir.util.fields
+import org.jetbrains.kotlin.ir.util.getAllSuperclasses
+import org.jetbrains.kotlin.ir.util.hasEqualFqName
+import org.jetbrains.kotlin.load.java.JvmAbi
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+
+internal val readResolveForDataObjectsPhase = makeIrFilePhase(
+    ::ReadResolveForDataObjectsLowering,
+    name = "ReadResolveForDataObjectsLowering",
+    description = "Generate readResolve for serializable data objects"
+)
+
+private class ReadResolveForDataObjectsLowering(val context: JvmBackendContext) : ClassLoweringPass {
+    override fun lower(irClass: IrClass) {
+        if (!context.state.languageVersionSettings.supportsFeature(LanguageFeature.DataObjects)) return
+
+        if (!irClass.isData || irClass.kind != ClassKind.OBJECT || !irClass.isSerializable()) return
+
+        context.irFactory.buildFun {
+            name = Name.identifier("readResolve")
+            modality = Modality.FINAL
+            origin = IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER
+            returnType = context.irBuiltIns.anyType
+            visibility = DescriptorVisibilities.PRIVATE
+        }.apply {
+            addDispatchReceiver { type = irClass.defaultType }
+            parent = irClass
+            body = context.createJvmIrBuilder(symbol).run {
+                val instanceField = irClass.fields.single { it.name.asString() == JvmAbi.INSTANCE_FIELD }
+                irExprBody(irGetField(null, instanceField))
+            }
+            irClass.declarations.add(this)
+        }
+    }
+}
+
+private val SERIALIZABLE_FQ_NAME = FqName("java.io.Serializable")
+
+private fun IrClass.isSerializable(): Boolean =
+    getAllSuperclasses().any { it.hasEqualFqName(SERIALIZABLE_FQ_NAME) }
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt
index facbe96..813c516 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt
@@ -74,8 +74,9 @@
         val origin: IrDeclarationOrigin
     ) : DataClassMethodGenerator(ktClassOrObject, declarationGenerator.context.bindingContext) {
 
-        private val irDataClassMembersGenerator =
-            object : DataClassMembersGenerator(context, context.symbolTable, irClass, origin, generateBodies = generateBodies) {
+        private val irDataClassMembersGenerator = object : DataClassMembersGenerator(
+            context, context.symbolTable, irClass, ktClassOrObject.fqName, origin, generateBodies = generateBodies
+        ) {
             override fun declareSimpleFunction(startOffset: Int, endOffset: Int, functionDescriptor: FunctionDescriptor): IrFunction =
                 declareSimpleFunction(startOffset, endOffset, origin, functionDescriptor)
 
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DataClassMembersGenerator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DataClassMembersGenerator.kt
index 8f07c29..c071eb2 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DataClassMembersGenerator.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DataClassMembersGenerator.kt
@@ -19,6 +19,7 @@
 import org.jetbrains.kotlin.ir.types.IrType
 import org.jetbrains.kotlin.ir.types.classifierOrNull
 import org.jetbrains.kotlin.ir.types.isNullable
+import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.name.Name
 
 /**
@@ -32,6 +33,7 @@
     val context: IrGeneratorContext,
     val symbolTable: ReferenceSymbolTable,
     val irClass: IrClass,
+    val fqName: FqName?,
     val origin: IrDeclarationOrigin,
     val forbidDirectFieldAccess: Boolean = false,
     val generateBodies: Boolean = false
@@ -139,9 +141,9 @@
             +irReturnTrue()
         }
 
-        fun generateHashCodeMethodBody(properties: List<IrProperty>) {
+        fun generateHashCodeMethodBody(properties: List<IrProperty>, constHashCode: Int) {
             if (properties.isEmpty()) {
-                +irReturn(irInt(0))
+                +irReturn(irInt(constHashCode))
                 return
             } else if (properties.size == 1) {
                 +irReturn(getHashCodeOfProperty(properties[0]))
@@ -186,6 +188,10 @@
         }
 
         fun generateToStringMethodBody(properties: List<IrProperty>) {
+            if (properties.isEmpty() && irClass.kind == ClassKind.OBJECT) {
+                +irReturn(irString(irClass.name.asString()))
+                return
+            }
             val irConcat = irConcat()
             irConcat.addArgument(irString(irClass.classNameForToString() + "("))
             var first = true
@@ -259,6 +265,7 @@
     ) {
         MemberFunctionBuilder(startOffset, endOffset, declareSimpleFunction(startOffset, endOffset, function)).addToClass { irFunction ->
             irFunction.buildWithScope {
+                irFunction.parent = irClass
                 generateSyntheticFunctionParameterDeclarations(irFunction)
                 body(irFunction)
             }
@@ -344,14 +351,20 @@
     // Entry for psi2ir
     fun generateHashCodeMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
         buildMember(function) {
-            generateHashCodeMethodBody(properties.map { getIrProperty(it) })
+            generateHashCodeMethodBody(
+                properties.map { getIrProperty(it) },
+                if (irClass.kind == ClassKind.OBJECT && irClass.isData) fqName.hashCode() else 0
+            )
         }
     }
 
     // Entry for fir2ir
     fun generateHashCodeMethod(irFunction: IrFunction, properties: List<IrProperty>) {
         buildMember(irFunction) {
-            generateHashCodeMethodBody(properties)
+            generateHashCodeMethodBody(
+                properties,
+                if (irClass.kind == ClassKind.OBJECT && irClass.isData) fqName.hashCode() else 0
+            )
         }
     }
 
diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClass.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClass.kt
index 9c88e1c..f26366f 100644
--- a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClass.kt
+++ b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClass.kt
@@ -29,7 +29,6 @@
         _stub?.isInterface() ?: (findChildByType<PsiElement>(KtTokens.INTERFACE_KEYWORD) != null)
 
     fun isEnum(): Boolean = hasModifier(KtTokens.ENUM_KEYWORD)
-    fun isData(): Boolean = hasModifier(KtTokens.DATA_KEYWORD)
     fun isSealed(): Boolean = hasModifier(KtTokens.SEALED_KEYWORD)
     fun isInner(): Boolean = hasModifier(KtTokens.INNER_KEYWORD)
     fun isInline(): Boolean = hasModifier(KtTokens.INLINE_KEYWORD)
diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassOrObject.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassOrObject.kt
index bbabbac..3cac8da 100644
--- a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassOrObject.kt
+++ b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassOrObject.kt
@@ -100,6 +100,8 @@
 
     override fun isLocal(): Boolean = stub?.isLocal() ?: KtPsiUtil.isLocal(this)
 
+    fun isData(): Boolean = hasModifier(KtTokens.DATA_KEYWORD)
+
     override fun getDeclarations(): List<KtDeclaration> = getBody()?.declarations.orEmpty()
 
     override fun getPresentation(): ItemPresentation? = ItemPresentationProviders.getItemPresentation(this)
diff --git a/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt b/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt
index 9215c55..13ef31f 100644
--- a/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt
+++ b/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt
@@ -132,7 +132,8 @@
     EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
     ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
     LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables),
-    FUN_KEYWORD to listOf(LanguageFeature.FunctionalInterfaceConversion)
+    FUN_KEYWORD to listOf(LanguageFeature.FunctionalInterfaceConversion),
+    DATA_KEYWORD to listOf(LanguageFeature.DataObjects)
 )
 
 val featureDependenciesTargets = mapOf(
@@ -141,7 +142,8 @@
     LanguageFeature.LateinitTopLevelProperties to setOf(KotlinTarget.TOP_LEVEL_PROPERTY),
     LanguageFeature.InlineClasses to setOf(KotlinTarget.CLASS_ONLY),
     LanguageFeature.JvmInlineValueClasses to setOf(KotlinTarget.CLASS_ONLY),
-    LanguageFeature.FunctionalInterfaceConversion to setOf(KotlinTarget.INTERFACE)
+    LanguageFeature.FunctionalInterfaceConversion to setOf(KotlinTarget.INTERFACE),
+    LanguageFeature.DataObjects to setOf(KotlinTarget.STANDALONE_OBJECT)
 )
 
 val defaultVisibilityTargets: EnumSet<KotlinTarget> = EnumSet.of(
@@ -204,7 +206,7 @@
         KotlinTarget.LOCAL_VARIABLE,
         KotlinTarget.BACKING_FIELD
     ),
-    DATA_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS),
+    DATA_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS, KotlinTarget.STANDALONE_OBJECT),
     INLINE_KEYWORD to EnumSet.of(
         KotlinTarget.FUNCTION,
         KotlinTarget.PROPERTY,
diff --git a/compiler/testData/codegen/box/dataObjects/equals.kt b/compiler/testData/codegen/box/dataObjects/equals.kt
new file mode 100644
index 0000000..90aa2ab
--- /dev/null
+++ b/compiler/testData/codegen/box/dataObjects/equals.kt
@@ -0,0 +1,15 @@
+// LANGUAGE: +DataObjects
+// WITH_STDLIB
+
+package com.example
+
+import kotlin.test.*
+
+data object DataObject
+
+fun box(): String {
+    assertEquals(DataObject, DataObject)
+    assertFalse(DataObject == null)
+
+    return  "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/dataObjects/hashCode.kt b/compiler/testData/codegen/box/dataObjects/hashCode.kt
new file mode 100644
index 0000000..ad2826e
--- /dev/null
+++ b/compiler/testData/codegen/box/dataObjects/hashCode.kt
@@ -0,0 +1,19 @@
+// LANGUAGE: +DataObjects
+// WITH_STDLIB
+
+package com.example
+
+import kotlin.test.*
+
+data object DataObject {
+    data object Inner
+}
+
+fun box(): String {
+    assertEquals(DataObject.hashCode(), DataObject.hashCode())
+    assertNotEquals(DataObject.hashCode(), DataObject.Inner.hashCode())
+    assertNotEquals(0, DataObject.hashCode())
+    assertNotEquals(0, DataObject.Inner.hashCode())
+
+    return "OK"
+}
diff --git a/compiler/testData/codegen/box/dataObjects/multipleInstances.kt b/compiler/testData/codegen/box/dataObjects/multipleInstances.kt
new file mode 100644
index 0000000..7b4c49e
--- /dev/null
+++ b/compiler/testData/codegen/box/dataObjects/multipleInstances.kt
@@ -0,0 +1,18 @@
+// LANGUAGE: +DataObjects
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+
+import kotlin.test.*
+
+data object DataObject
+
+val doppelganger = DataObject::class.java.declaredConstructors[0].apply { isAccessible = true }.newInstance()
+
+fun box(): String {
+    assertFalse(DataObject === doppelganger)
+    assertEquals(DataObject, doppelganger)
+    assertEquals(DataObject.hashCode(), DataObject::class.java.cast(doppelganger).hashCode())
+
+    return  "OK"
+}
+
diff --git a/compiler/testData/codegen/box/dataObjects/serialization.kt b/compiler/testData/codegen/box/dataObjects/serialization.kt
new file mode 100644
index 0000000..62eb0d0
--- /dev/null
+++ b/compiler/testData/codegen/box/dataObjects/serialization.kt
@@ -0,0 +1,19 @@
+// LANGUAGE: +DataObjects
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// FULL_JDK
+// CHECK_BYTECODE_LISTING
+
+import java.io.*
+
+data object NonSerializableDataObject
+
+data object SerializableDataObject: Serializable
+
+fun box(): String {
+    ByteArrayOutputStream().use { baos ->
+        ObjectOutputStream(baos).use { oos -> oos.writeObject(SerializableDataObject) }
+        ByteArrayInputStream(baos.toByteArray()).use { bais -> assert(java.io.ObjectInputStream(bais).readObject() === SerializableDataObject) }
+    }
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/dataObjects/serialization.txt b/compiler/testData/codegen/box/dataObjects/serialization.txt
new file mode 100644
index 0000000..429be3e
--- /dev/null
+++ b/compiler/testData/codegen/box/dataObjects/serialization.txt
@@ -0,0 +1,28 @@
+@kotlin.Metadata
+public final class NonSerializableDataObject {
+    // source: 'serialization.kt'
+    public final static @org.jetbrains.annotations.NotNull field INSTANCE: NonSerializableDataObject
+    static method <clinit>(): void
+    private method <init>(): void
+    public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
+    public method hashCode(): int
+    public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
+}
+
+@kotlin.Metadata
+public final class SerializableDataObject {
+    // source: 'serialization.kt'
+    public final static @org.jetbrains.annotations.NotNull field INSTANCE: SerializableDataObject
+    static method <clinit>(): void
+    private method <init>(): void
+    public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
+    public method hashCode(): int
+    private final method readResolve(): java.lang.Object
+    public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
+}
+
+@kotlin.Metadata
+public final class SerializationKt {
+    // source: 'serialization.kt'
+    public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
+}
diff --git a/compiler/testData/codegen/box/dataObjects/toString.kt b/compiler/testData/codegen/box/dataObjects/toString.kt
new file mode 100644
index 0000000..7819b09
--- /dev/null
+++ b/compiler/testData/codegen/box/dataObjects/toString.kt
@@ -0,0 +1,52 @@
+// LANGUAGE: +DataObjects
+// WITH_STDLIB
+
+package com.example
+
+import kotlin.test.*
+
+data object DataObject {
+    data object Nested
+}
+
+class Foo {
+    data object Inner
+}
+
+data object Declared {
+    override fun toString() = "Overriden"
+}
+
+open class WithFinalToString {
+    final override fun toString() = "FinalToString"
+}
+
+data object InheritedFromClassWithFinalToString: WithFinalToString()
+
+open class WithOpenToString {
+    override fun toString() = "OpenToString"
+}
+
+data object InheritedFromClassWithOpenToString: WithOpenToString()
+
+abstract class WithAbstractToString {
+    abstract override fun toString(): String
+}
+
+data object InheritedFromClassWithAbstractToString : WithAbstractToString()
+
+class C {
+    companion object CC
+}
+
+fun box(): String {
+    assertEquals("DataObject", DataObject.toString())
+    assertEquals("Nested", DataObject.Nested.toString())
+    assertEquals("Inner", Foo.Inner.toString())
+    assertEquals("Overriden", Declared.toString())
+    assertEquals("FinalToString", InheritedFromClassWithFinalToString.toString())
+    assertEquals("InheritedFromClassWithOpenToString", InheritedFromClassWithOpenToString.toString())
+    assertEquals("InheritedFromClassWithAbstractToString", InheritedFromClassWithAbstractToString.toString())
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt b/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt
new file mode 100644
index 0000000..8d7726b
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt
@@ -0,0 +1,6 @@
+// FIR_IDENTICAL
+// LANGUAGE: +DataObjects
+
+class C {
+    companion <!WRONG_MODIFIER_TARGET!>data<!> object Object
+}
diff --git a/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.txt b/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.txt
new file mode 100644
index 0000000..cf0fb1a
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.txt
@@ -0,0 +1,16 @@
+package
+
+public final class C {
+    public constructor C()
+    public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+
+    public data companion object Object {
+        private constructor Object()
+        public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+        public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
+        public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+    }
+}
+
diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObject.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObject.kt
deleted file mode 100644
index 2c99760..0000000
--- a/compiler/testData/diagnostics/tests/dataClasses/dataObject.kt
+++ /dev/null
@@ -1,2 +0,0 @@
-// FIR_IDENTICAL
-<!WRONG_MODIFIER_TARGET!>data<!> object Object<!CONSTRUCTOR_IN_OBJECT!>(val x: Int, val y: Int)<!>
diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObject.txt b/compiler/testData/diagnostics/tests/dataClasses/dataObject.txt
deleted file mode 100644
index b270a54..0000000
--- a/compiler/testData/diagnostics/tests/dataClasses/dataObject.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-package
-
-public data object Object {
-    private constructor Object(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int)
-    public final val x: kotlin.Int
-    public final val y: kotlin.Int
-    public final operator /*synthesized*/ fun component1(): kotlin.Int
-    public final operator /*synthesized*/ fun component2(): kotlin.Int
-    public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.Int = ...): Object
-    public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
-    public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
-    public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
-}
diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.fir.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.fir.kt
new file mode 100644
index 0000000..dfa99ea
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.fir.kt
@@ -0,0 +1,2 @@
+// LANGUAGE: -DataObjects
+<!WRONG_MODIFIER_TARGET!>data<!> object Object
diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt
new file mode 100644
index 0000000..782e17f
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt
@@ -0,0 +1,2 @@
+// LANGUAGE: -DataObjects
+<!UNSUPPORTED_FEATURE!>data<!> object Object
diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.txt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.txt
new file mode 100644
index 0000000..71427a2
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.txt
@@ -0,0 +1,9 @@
+package
+
+public data object Object {
+    private constructor Object()
+    public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+}
+
diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt
new file mode 100644
index 0000000..4046975
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt
@@ -0,0 +1,3 @@
+// LANGUAGE: +DataObjects
+// FIR_IDENTICAL
+data object Object
diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.txt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.txt
new file mode 100644
index 0000000..71427a2
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.txt
@@ -0,0 +1,9 @@
+package
+
+public data object Object {
+    private constructor Object()
+    public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+}
+
diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt
new file mode 100644
index 0000000..c80e42f
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt
@@ -0,0 +1,10 @@
+// FIR_IDENTICAL
+// LANGUAGE: +DataObjects
+
+interface I {
+    fun foo()
+}
+
+val o = <!UNRESOLVED_REFERENCE!>data<!><!SYNTAX!><!> object<!SYNTAX!><!>: I {
+    override fun foo() {}
+}
diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.txt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.txt
new file mode 100644
index 0000000..f624cf4
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.txt
@@ -0,0 +1,18 @@
+package
+
+public val o: [Error type: Not found recorded type for data]
+
+public object `<no name provided>` : I {
+    private constructor `<no name provided>`()
+    public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ fun foo(): kotlin.Unit
+    public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
+public interface I {
+    public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public abstract fun foo(): kotlin.Unit
+    public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
diff --git a/compiler/testData/diagnostics/tests/dataClasses/strange.kt b/compiler/testData/diagnostics/tests/dataClasses/strange.kt
index a181e42..0998adc 100644
--- a/compiler/testData/diagnostics/tests/dataClasses/strange.kt
+++ b/compiler/testData/diagnostics/tests/dataClasses/strange.kt
@@ -3,8 +3,8 @@
     B(2)
 }
 
-<!WRONG_MODIFIER_TARGET!>data<!> object <!DATA_CLASS_WITHOUT_PARAMETERS!>Second<!>
+<!UNSUPPORTED_FEATURE!>data<!> object Second
 
-<!WRONG_MODIFIER_TARGET!>data<!> interface <!DATA_CLASS_WITHOUT_PARAMETERS!>Third<!>
+<!WRONG_MODIFIER_TARGET!>data<!> interface Third
 
-<!WRONG_MODIFIER_TARGET!>data<!> annotation class Fourth(val x: Int)
\ No newline at end of file
+<!WRONG_MODIFIER_TARGET!>data<!> annotation class Fourth(val x: Int)
diff --git a/compiler/testData/diagnostics/tests/dataClasses/strange.txt b/compiler/testData/diagnostics/tests/dataClasses/strange.txt
index 7531d4d..57fd6e3 100644
--- a/compiler/testData/diagnostics/tests/dataClasses/strange.txt
+++ b/compiler/testData/diagnostics/tests/dataClasses/strange.txt
@@ -11,8 +11,6 @@
     public final val x: kotlin.Int
     protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
     public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: First): kotlin.Int
-    public final operator /*synthesized*/ fun component1(): kotlin.Int
-    public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ...): First
     public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
     protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
     public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<First!>!
@@ -27,8 +25,6 @@
 public final data annotation class Fourth : kotlin.Annotation {
     public constructor Fourth(/*0*/ x: kotlin.Int)
     public final val x: kotlin.Int
-    public final operator /*synthesized*/ fun component1(): kotlin.Int
-    public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ...): Fourth
     public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
     public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
     public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
@@ -36,7 +32,6 @@
 
 public data object Second {
     private constructor Second()
-    public final /*synthesized*/ fun copy(): Second
     public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
     public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
     public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
@@ -47,3 +42,4 @@
     public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
     public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
 }
+
diff --git a/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt b/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt
new file mode 100644
index 0000000..a3a780b
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt
@@ -0,0 +1,44 @@
+// FIR_IDENTICAL
+// LANGUAGE: +DataObjects
+
+data object Override {
+    <!DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE!>override<!> fun equals(other: Any?): Boolean {
+        return true
+    }
+
+    <!DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE!>override<!> fun hashCode(): Int {
+        return 1
+    }
+}
+
+open class Base {
+    open fun hashCode(x: Int) = x
+}
+
+data object NoOverride: Base() {
+    fun equals(other: Any?, tag: Int): Boolean {
+        return true
+    }
+
+    fun hashCode(param: String): Int {
+        return 1
+    }
+
+    override fun hashCode(x: Int) = x + 1
+}
+
+open class Super {
+    override fun equals(other: Any?): Boolean {
+        return super.equals(other)
+    }
+
+    override fun hashCode(): Int {
+        return 1
+    }
+}
+
+data object OverridenInSuper: Super() {
+    <!DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE!>override<!> fun equals(other: Any?): Boolean {
+        return super.equals(other)
+    }
+}
diff --git a/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.txt b/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.txt
new file mode 100644
index 0000000..49dfff5
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.txt
@@ -0,0 +1,40 @@
+package
+
+public open class Base {
+    public constructor Base()
+    public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+    public open fun hashCode(/*0*/ x: kotlin.Int): kotlin.Int
+    public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
+public data object NoOverride : Base {
+    private constructor NoOverride()
+    public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public final fun equals(/*0*/ other: kotlin.Any?, /*1*/ tag: kotlin.Int): kotlin.Boolean
+    public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ fun hashCode(/*0*/ x: kotlin.Int): kotlin.Int
+    public final fun hashCode(/*0*/ param: kotlin.String): kotlin.Int
+    public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+}
+
+public data object Override {
+    private constructor Override()
+    public open override /*1*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+}
+
+public data object OverridenInSuper : Super {
+    private constructor OverridenInSuper()
+    public open override /*1*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+}
+
+public open class Super {
+    public constructor Super()
+    public open override /*1*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.kt b/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.kt
new file mode 100644
index 0000000..a4d5363
--- /dev/null
+++ b/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.kt
@@ -0,0 +1,16 @@
+// !LANGUAGE: +DataObjects
+// TARGET_BACKEND: JVM_IR
+
+import java.io.Serializable
+
+data <!CONFLICTING_JVM_DECLARATIONS!>object A<!> : Serializable {
+    <!CONFLICTING_JVM_DECLARATIONS!>private fun readResolve(): Any<!> = this
+}
+
+data object B : Serializable {
+    private fun readResolve(): B = this
+}
+
+data object C {
+    private fun readResolve(): Any = this
+}
diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.txt b/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.txt
new file mode 100644
index 0000000..ec615f4
--- /dev/null
+++ b/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.txt
@@ -0,0 +1,26 @@
+package
+
+public data object A : java.io.Serializable {
+    private constructor A()
+    public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
+    private final fun readResolve(): kotlin.Any
+    public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+}
+
+public data object B : java.io.Serializable {
+    private constructor B()
+    public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
+    private final fun readResolve(): B
+    public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+}
+
+public data object C {
+    private constructor C()
+    public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
+    private final fun readResolve(): kotlin.Any
+    public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+}
+
diff --git a/compiler/testData/ir/irText/declarations/parameters/dataClassMembers.fir.kt.txt b/compiler/testData/ir/irText/declarations/parameters/dataClassMembers.fir.kt.txt
index 99ac9bd..6d3ce06 100644
--- a/compiler/testData/ir/irText/declarations/parameters/dataClassMembers.fir.kt.txt
+++ b/compiler/testData/ir/irText/declarations/parameters/dataClassMembers.fir.kt.txt
@@ -56,3 +56,4 @@
   }
 
 }
+
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java
index 7337e3d..0117bd2 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java
@@ -6963,6 +6963,12 @@
             }
 
             @Test
+            @TestMetadata("companionDataObject.kt")
+            public void testCompanionDataObject() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt");
+            }
+
+            @Test
             @TestMetadata("componentNamedComponent1.kt")
             public void testComponentNamedComponent1() throws Exception {
                 runTest("compiler/testData/diagnostics/tests/dataClasses/componentNamedComponent1.kt");
@@ -7035,9 +7041,21 @@
             }
 
             @Test
-            @TestMetadata("dataObject.kt")
-            public void testDataObject() throws Exception {
-                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObject.kt");
+            @TestMetadata("dataObjectDisabled.kt")
+            public void testDataObjectDisabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt");
+            }
+
+            @Test
+            @TestMetadata("dataObjectEnabled.kt")
+            public void testDataObjectEnabled() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt");
+            }
+
+            @Test
+            @TestMetadata("dataObjectLiteral.kt")
+            public void testDataObjectLiteral() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt");
             }
 
             @Test
@@ -7662,6 +7680,22 @@
         }
 
         @Nested
+        @TestMetadata("compiler/testData/diagnostics/tests/dataObjects")
+        @TestDataPath("$PROJECT_ROOT")
+        public class DataObjects {
+            @Test
+            public void testAllFilesPresentInDataObjects() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataObjects"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
+            }
+
+            @Test
+            @TestMetadata("overrideEqualsAndHashCode.kt")
+            public void testOverrideEqualsAndHashCode() throws Exception {
+                runTest("compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt");
+            }
+        }
+
+        @Nested
         @TestMetadata("compiler/testData/diagnostics/tests/declarationChecks")
         @TestDataPath("$PROJECT_ROOT")
         public class DeclarationChecks {
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java
index 4d18425..c1de6f2 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java
@@ -62,6 +62,22 @@
     }
 
     @Nested
+    @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects")
+    @TestDataPath("$PROJECT_ROOT")
+    public class DataObjects {
+        @Test
+        public void testAllFilesPresentInDataObjects() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects"), Pattern.compile("^(.+)\\.kts?$"), null, TargetBackend.JVM_IR, true);
+        }
+
+        @Test
+        @TestMetadata("customReadResolve.kt")
+        public void testCustomReadResolve() throws Exception {
+            runTest("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.kt");
+        }
+    }
+
+    @Nested
     @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/duplicateJvmSignature")
     @TestDataPath("$PROJECT_ROOT")
     public class DuplicateJvmSignature {
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java
index 038a0d5..573d9c4 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java
@@ -62,6 +62,16 @@
     }
 
     @Nested
+    @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects")
+    @TestDataPath("$PROJECT_ROOT")
+    public class DataObjects {
+        @Test
+        public void testAllFilesPresentInDataObjects() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_OLD, true);
+        }
+    }
+
+    @Nested
     @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/duplicateJvmSignature")
     @TestDataPath("$PROJECT_ROOT")
     public class DuplicateJvmSignature {
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java
index 310bcc0..bf84b14 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java
@@ -13529,6 +13529,34 @@
     }
 
     @Nested
+    @TestMetadata("compiler/testData/codegen/box/dataObjects")
+    @TestDataPath("$PROJECT_ROOT")
+    public class DataObjects {
+        @Test
+        public void testAllFilesPresentInDataObjects() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
+        }
+
+        @Test
+        @TestMetadata("equals.kt")
+        public void testEquals() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/equals.kt");
+        }
+
+        @Test
+        @TestMetadata("hashCode.kt")
+        public void testHashCode() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt");
+        }
+
+        @Test
+        @TestMetadata("toString.kt")
+        public void testToString() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/toString.kt");
+        }
+    }
+
+    @Nested
     @TestMetadata("compiler/testData/codegen/box/deadCodeElimination")
     @TestDataPath("$PROJECT_ROOT")
     public class DeadCodeElimination {
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
index b3c8351..7cbcafd 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
@@ -13649,6 +13649,46 @@
     }
 
     @Nested
+    @TestMetadata("compiler/testData/codegen/box/dataObjects")
+    @TestDataPath("$PROJECT_ROOT")
+    public class DataObjects {
+        @Test
+        public void testAllFilesPresentInDataObjects() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+        }
+
+        @Test
+        @TestMetadata("equals.kt")
+        public void testEquals() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/equals.kt");
+        }
+
+        @Test
+        @TestMetadata("hashCode.kt")
+        public void testHashCode() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt");
+        }
+
+        @Test
+        @TestMetadata("multipleInstances.kt")
+        public void testMultipleInstances() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/multipleInstances.kt");
+        }
+
+        @Test
+        @TestMetadata("serialization.kt")
+        public void testSerialization() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/serialization.kt");
+        }
+
+        @Test
+        @TestMetadata("toString.kt")
+        public void testToString() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/toString.kt");
+        }
+    }
+
+    @Nested
     @TestMetadata("compiler/testData/codegen/box/deadCodeElimination")
     @TestDataPath("$PROJECT_ROOT")
     public class DeadCodeElimination {
diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
index fed2f732..aaa8874 100644
--- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
+++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
@@ -10981,6 +10981,34 @@
         }
     }
 
+    @TestMetadata("compiler/testData/codegen/box/dataObjects")
+    @TestDataPath("$PROJECT_ROOT")
+    @RunWith(JUnit3RunnerWithInners.class)
+    public static class DataObjects extends AbstractLightAnalysisModeTest {
+        private void runTest(String testDataFilePath) throws Exception {
+            KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
+        }
+
+        public void testAllFilesPresentInDataObjects() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
+        }
+
+        @TestMetadata("equals.kt")
+        public void testEquals() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/equals.kt");
+        }
+
+        @TestMetadata("hashCode.kt")
+        public void testHashCode() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt");
+        }
+
+        @TestMetadata("toString.kt")
+        public void testToString() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/toString.kt");
+        }
+    }
+
     @TestMetadata("compiler/testData/codegen/box/deadCodeElimination")
     @TestDataPath("$PROJECT_ROOT")
     @RunWith(JUnit3RunnerWithInners.class)
diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
index be45645..c96fe94 100644
--- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
+++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
@@ -263,6 +263,7 @@
     RefineTypeCheckingOnAssignmentsToJavaFields(KOTLIN_1_8, kind = BUG_FIX),
     RangeUntilOperator(KOTLIN_1_8), // KT-15613
     GenericInlineClassParameter(sinceVersion = KOTLIN_1_8, kind = UNSTABLE_FEATURE), // KT-32162
+    DataObjects(KOTLIN_1_8), // KT-4107
 
     // 1.9
 
diff --git a/core/compiler.common/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt b/core/compiler.common/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt
index b9525cb1..61bf33b 100644
--- a/core/compiler.common/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt
+++ b/core/compiler.common/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt
@@ -34,8 +34,9 @@
     // includes only top level classes and nested/inner classes (but not enums, objects, interfaces and local classes)
     CLASS_ONLY("class", false),
 
-    // does not include OBJECT_LITERAL but DOES include COMPANION_OBJECT
+    // does not include OBJECT_LITERAL but DOES include both STANDALONE_OBJECT and COMPANION_OBJECT
     OBJECT("object", false),
+    STANDALONE_OBJECT("standalone object", false),
     COMPANION_OBJECT("companion object", false),
     INTERFACE("interface", false),
     ENUM_CLASS("enum class", false),
@@ -84,7 +85,7 @@
         val LOCAL_CLASS_LIST = listOf(LOCAL_CLASS, CLASS)
         val CLASS_LIST = listOf(CLASS_ONLY, CLASS)
         val COMPANION_OBJECT_LIST = listOf(COMPANION_OBJECT, OBJECT, CLASS)
-        val OBJECT_LIST = listOf(OBJECT, CLASS)
+        val OBJECT_LIST = listOf(STANDALONE_OBJECT, OBJECT, CLASS)
         val INTERFACE_LIST = listOf(INTERFACE, CLASS)
         val ENUM_LIST = listOf(ENUM_CLASS, CLASS)
         val ENUM_ENTRY_LIST = listOf(ENUM_ENTRY, PROPERTY, FIELD)
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java
index c61fa00..4808038 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java
@@ -10117,6 +10117,34 @@
     }
 
     @Nested
+    @TestMetadata("compiler/testData/codegen/box/dataObjects")
+    @TestDataPath("$PROJECT_ROOT")
+    public class DataObjects {
+        @Test
+        public void testAllFilesPresentInDataObjects() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
+        }
+
+        @Test
+        @TestMetadata("equals.kt")
+        public void testEquals() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/equals.kt");
+        }
+
+        @Test
+        @TestMetadata("hashCode.kt")
+        public void testHashCode() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt");
+        }
+
+        @Test
+        @TestMetadata("toString.kt")
+        public void testToString() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/toString.kt");
+        }
+    }
+
+    @Nested
     @TestMetadata("compiler/testData/codegen/box/deadCodeElimination")
     @TestDataPath("$PROJECT_ROOT")
     public class DeadCodeElimination {
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java
index 7018d4d..8ee5a65 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java
@@ -10159,6 +10159,34 @@
     }
 
     @Nested
+    @TestMetadata("compiler/testData/codegen/box/dataObjects")
+    @TestDataPath("$PROJECT_ROOT")
+    public class DataObjects {
+        @Test
+        public void testAllFilesPresentInDataObjects() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
+        }
+
+        @Test
+        @TestMetadata("equals.kt")
+        public void testEquals() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/equals.kt");
+        }
+
+        @Test
+        @TestMetadata("hashCode.kt")
+        public void testHashCode() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt");
+        }
+
+        @Test
+        @TestMetadata("toString.kt")
+        public void testToString() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/toString.kt");
+        }
+    }
+
+    @Nested
     @TestMetadata("compiler/testData/codegen/box/deadCodeElimination")
     @TestDataPath("$PROJECT_ROOT")
     public class DeadCodeElimination {
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
index 623c73f..108acbd 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
@@ -8996,6 +8996,34 @@
         }
     }
 
+    @TestMetadata("compiler/testData/codegen/box/dataObjects")
+    @TestDataPath("$PROJECT_ROOT")
+    @RunWith(JUnit3RunnerWithInners.class)
+    public static class DataObjects extends AbstractIrCodegenBoxWasmTest {
+        private void runTest(String testDataFilePath) throws Exception {
+            KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+        }
+
+        public void testAllFilesPresentInDataObjects() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
+        }
+
+        @TestMetadata("equals.kt")
+        public void testEquals() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/equals.kt");
+        }
+
+        @TestMetadata("hashCode.kt")
+        public void testHashCode() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt");
+        }
+
+        @TestMetadata("toString.kt")
+        public void testToString() throws Exception {
+            runTest("compiler/testData/codegen/box/dataObjects/toString.kt");
+        }
+    }
+
     @TestMetadata("compiler/testData/codegen/box/deadCodeElimination")
     @TestDataPath("$PROJECT_ROOT")
     @RunWith(JUnit3RunnerWithInners.class)
diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsEqualsHashcodeToStringGenerator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsEqualsHashcodeToStringGenerator.java
index 22ada7d..f71b755 100644
--- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsEqualsHashcodeToStringGenerator.java
+++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsEqualsHashcodeToStringGenerator.java
@@ -16,7 +16,9 @@
 import org.jetbrains.kotlin.js.translate.context.TranslationContext;
 import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
 import org.jetbrains.kotlin.js.translate.utils.UtilsKt;
+import org.jetbrains.kotlin.name.FqName;
 import org.jetbrains.kotlin.psi.KtClassOrObject;
+import org.jetbrains.kotlin.psi.KtObjectDeclaration;
 import org.jetbrains.kotlin.psi.KtParameter;
 import org.jetbrains.kotlin.resolve.source.PsiSourceElementKt;
 
@@ -35,6 +37,11 @@
 
     @Override
     public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> classProperties) {
+        if (getDeclaration() instanceof KtObjectDeclaration) {
+            generateJsMethod(function).getBody().getStatements().add(new JsReturn(new JsStringLiteral(getDeclaration().getName())));
+            return;
+        }
+
         // TODO: relax this limitation, with the data generation logic fixed.
         assert !classProperties.isEmpty();
         JsFunction functionObj = generateJsMethod(function);
@@ -65,6 +72,14 @@
     @Override
     public void generateHashCodeMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> classProperties) {
         JsFunction functionObj = generateJsMethod(function);
+        if (classProperties.isEmpty()) {
+            FqName fqName = getDeclaration().getFqName();
+            JsExpression returnExpression = new JsIntLiteral(fqName != null ? fqName.hashCode() : 0);
+            JsReturn returnStatement = new JsReturn(returnExpression);
+            returnStatement.setSource(getDeclaration());
+            functionObj.getBody().getStatements().add(returnStatement);
+            return;
+        }
 
         List<JsStatement> statements = functionObj.getBody().getStatements();
 
@@ -92,8 +107,8 @@
 
     @Override
     public void generateEqualsMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> classProperties) {
-        assert !classProperties.isEmpty();
         JsFunction functionObj = generateJsMethod(function);
+
         JsFunctionScope funScope = functionObj.getScope();
 
         JsName paramName = funScope.declareName("other");
@@ -120,9 +135,8 @@
                 fieldChain = and(fieldChain, next);
             }
         }
-        assert fieldChain != null;
 
-        JsExpression returnExpression = or(referenceEqual, and(isNotNull, and(otherIsObject, and(prototypeEqual, fieldChain))));
+        JsExpression returnExpression = or(referenceEqual, and(isNotNull, and(otherIsObject, fieldChain != null ? and(prototypeEqual, fieldChain) : prototypeEqual)));
         JsReturn returnStatement = new JsReturn(returnExpression);
         returnStatement.setSource(getDeclaration());
         functionObj.getBody().getStatements().add(returnStatement);
diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java
index 9dd93e7..dfa5f1b 100644
--- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java
+++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java
@@ -11103,6 +11103,36 @@
         }
 
         @Nested
+        @TestMetadata("compiler/testData/codegen/box/dataObjects")
+        @TestDataPath("$PROJECT_ROOT")
+        @Tag("codegen")
+        @UseExtTestCaseGroupProvider()
+        public class DataObjects {
+            @Test
+            public void testAllFilesPresentInDataObjects() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
+            }
+
+            @Test
+            @TestMetadata("equals.kt")
+            public void testEquals() throws Exception {
+                runTest("compiler/testData/codegen/box/dataObjects/equals.kt");
+            }
+
+            @Test
+            @TestMetadata("hashCode.kt")
+            public void testHashCode() throws Exception {
+                runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt");
+            }
+
+            @Test
+            @TestMetadata("toString.kt")
+            public void testToString() throws Exception {
+                runTest("compiler/testData/codegen/box/dataObjects/toString.kt");
+            }
+        }
+
+        @Nested
         @TestMetadata("compiler/testData/codegen/box/deadCodeElimination")
         @TestDataPath("$PROJECT_ROOT")
         @Tag("codegen")
diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt
index 47748c4..3c90a9a 100644
--- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt
+++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt
@@ -32,7 +32,7 @@
     annotation class Type
 
     @Type
-    data class Group(s: String)
+    data class Group(var s: String)
 }
 
 class Foo {
diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.txt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.txt
index d59a60b..b954ee0 100644
--- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.txt
+++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.txt
@@ -100,6 +100,8 @@
     @kotlin.Metadata()
     @Experiment.Type()
     public static final class Group {
+        @org.jetbrains.annotations.NotNull()
+        private java.lang.String s;
 
         @org.jetbrains.annotations.NotNull()
         public final Experiment.Group copy(@org.jetbrains.annotations.NotNull()
@@ -107,10 +109,41 @@
             return null;
         }
 
+        @java.lang.Override()
+        public boolean equals(@org.jetbrains.annotations.Nullable()
+        java.lang.Object other) {
+            return false;
+        }
+
+        @java.lang.Override()
+        public int hashCode() {
+            return 0;
+        }
+
+        @org.jetbrains.annotations.NotNull()
+        @java.lang.Override()
+        public java.lang.String toString() {
+            return null;
+        }
+
         public Group(@org.jetbrains.annotations.NotNull()
         java.lang.String s) {
             super();
         }
+
+        @org.jetbrains.annotations.NotNull()
+        public final java.lang.String component1() {
+            return null;
+        }
+
+        @org.jetbrains.annotations.NotNull()
+        public final java.lang.String getS() {
+            return null;
+        }
+
+        public final void setS(@org.jetbrains.annotations.NotNull()
+        java.lang.String p0) {
+        }
     }
 }
 
diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2_ir.txt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2_ir.txt
index 3805239..cf445ac 100644
--- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2_ir.txt
+++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2_ir.txt
@@ -100,6 +100,8 @@
     @kotlin.Metadata()
     @Experiment.Type()
     public static final class Group {
+        @org.jetbrains.annotations.NotNull()
+        private java.lang.String s;
 
         public Group(@org.jetbrains.annotations.NotNull()
         java.lang.String s) {
@@ -107,6 +109,20 @@
         }
 
         @org.jetbrains.annotations.NotNull()
+        public final java.lang.String getS() {
+            return null;
+        }
+
+        public final void setS(@org.jetbrains.annotations.NotNull()
+        java.lang.String p0) {
+        }
+
+        @org.jetbrains.annotations.NotNull()
+        public final java.lang.String component1() {
+            return null;
+        }
+
+        @org.jetbrains.annotations.NotNull()
         public final Experiment.Group copy(@org.jetbrains.annotations.NotNull()
         java.lang.String s) {
             return null;
diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt
index 22d71e1..e9223f4 100644
--- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt
+++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt
@@ -38,7 +38,7 @@
     annotation class Type
 
     @Type
-    data class Group(s: String)
+    data class Group(val s: String)
 }
 
 class Foo {
diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.txt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.txt
index d720558..e743d18 100644
--- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.txt
+++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.txt
@@ -103,6 +103,8 @@
     @kotlin.Metadata()
     @test.Experiment.Type()
     public static final class Group {
+        @org.jetbrains.annotations.NotNull()
+        private final java.lang.String s = null;
 
         @org.jetbrains.annotations.NotNull()
         public final test.Experiment.Group copy(@org.jetbrains.annotations.NotNull()
@@ -110,10 +112,37 @@
             return null;
         }
 
+        @java.lang.Override()
+        public boolean equals(@org.jetbrains.annotations.Nullable()
+        java.lang.Object other) {
+            return false;
+        }
+
+        @java.lang.Override()
+        public int hashCode() {
+            return 0;
+        }
+
+        @org.jetbrains.annotations.NotNull()
+        @java.lang.Override()
+        public java.lang.String toString() {
+            return null;
+        }
+
         public Group(@org.jetbrains.annotations.NotNull()
         java.lang.String s) {
             super();
         }
+
+        @org.jetbrains.annotations.NotNull()
+        public final java.lang.String component1() {
+            return null;
+        }
+
+        @org.jetbrains.annotations.NotNull()
+        public final java.lang.String getS() {
+            return null;
+        }
     }
 }
 
diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage_ir.txt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage_ir.txt
index 2150b45..2878030 100644
--- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage_ir.txt
+++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage_ir.txt
@@ -103,6 +103,8 @@
     @kotlin.Metadata()
     @test.Experiment.Type()
     public static final class Group {
+        @org.jetbrains.annotations.NotNull()
+        private final java.lang.String s = null;
 
         public Group(@org.jetbrains.annotations.NotNull()
         java.lang.String s) {
@@ -110,6 +112,16 @@
         }
 
         @org.jetbrains.annotations.NotNull()
+        public final java.lang.String getS() {
+            return null;
+        }
+
+        @org.jetbrains.annotations.NotNull()
+        public final java.lang.String component1() {
+            return null;
+        }
+
+        @org.jetbrains.annotations.NotNull()
         public final test.Experiment.Group copy(@org.jetbrains.annotations.NotNull()
         java.lang.String s) {
             return null;