Apex API 61: No More Private Method Overriding?

Apex API 61: No More Private Method Overriding?

On June 22, 2025, Posted by , In Apex,Salesforce, By ,,, , With Comments Off on Apex API 61: No More Private Method Overriding?

Question

After upgrading from API version 60.0 to 61.0, I noticed an unexpected change in the behavior of inheritance for inner classes in Apex. Specifically, I observed that private methods in a superclass are no longer overridden by an inner class in the subclass when both methods have the same signature. This change appears to affect polymorphic behavior, where the subclass method should have been called when assigning the subclass instance to a superclass variable.

In API version 60.0 and earlier, you could declare a private virtual method in a superclass and override it in a subclass. When you instantiate the subclass and assign it to a variable of the superclass type, it would correctly call the overridden method in the subclass, not the superclass method.

However, in API version 61.0, this behavior seems to have changed. Below is an example that demonstrates the difference in behavior between API versions 60.0 and 61.0:

public class Superclass1 {
    private virtual String myMethod() {
        return 'Superclass1';
    }
}

public class Subclass2 extends Superclass1 {
    private override String myMethod() {
        return 'Subclass2';
    }
}

Superclass1 instanceOf1 = new Superclass1();
Superclass1 instanceOf2 = new Subclass2();

System.debug('Class 1: ' + instanceOf1.myMethod());
System.debug('Class 2: ' + instanceOf2.myMethod());

Expected Output for API version 60.0:

Class 1: Superclass1
Class 2: Subclass2

Actual Output for API version 61.0:

Class 1: Superclass1
Class 2: Superclass1

Upon further investigation using the Apex Replay Debugger, I found that in API version 60.0, the method call enters Subclass2, but in version 61.0, it enters Superclass1 instead.

Is this behavior a deliberate change introduced in API version 61.0? Or could this be a bug?

Answer

The change you observed is intentional and was introduced as part of the Summer ’24 release. In API version 61.0 and later, Salesforce altered how private methods behave with respect to inheritance. Previously, in API version 60.0 and earlier, a subclass could declare a method with the same signature as a private method in its superclass and effectively override it. However, starting with API version 61.0, private methods in a superclass can no longer be overridden by a method in a subclass, even if the methods have the same signature.

What’s Changed?

In earlier versions (API 60.0 and below), Salesforce allowed overriding private methods in subclasses. Specifically, you could define a private virtual method in a superclass and override it in an inner subclass. When you assigned an instance of the subclass to a variable of the superclass type, Salesforce’s runtime would respect polymorphism and call the overridden method in the subclass, not the original private method in the superclass.

For example, consider the following code snippet:

public class Superclass1 {
    private virtual String myMethod() {
        return 'Superclass1';
    }
}

public class Subclass2 extends Superclass1 {
    private override String myMethod() {
        return 'Subclass2';
    }
}

Superclass1 instanceOf1 = new Superclass1();
Superclass1 instanceOf2 = new Subclass2();

System.debug('Class 1: ' + instanceOf1.myMethod());  // Expected: Superclass1
System.debug('Class 2: ' + instanceOf2.myMethod());  // Expected: Subclass2

In API version 60.0, the expected output would be:

Class 1: Superclass1
Class 2: Subclass2

This works because Subclass2 correctly overrides the private method in Superclass1, and the method call on instanceOf2 (which points to a Subclass2 instance) invokes the overridden method in the subclass.

Why Did This Change in Version 61.0?

With API version 61.0, Salesforce decided to tighten the behavior of private methods and how they can be overridden. This change was made to improve encapsulation and to ensure that private methods remain truly private within the scope of their class. As a result, private methods are no longer polymorphic or subject to overriding by instance methods in subclasses. The method in the subclass with the same signature won’t override the method in the superclass if the method is marked as private.

So, when you run the same code on API version 61.0, the behavior changes:

public class Superclass1 {
    private virtual String myMethod() {
        return 'Superclass1';
    }
}

public class Subclass2 extends Superclass1 {
    private override String myMethod() {
        return 'Subclass2';
    }
}

Superclass1 instanceOf1 = new Superclass1();
Superclass1 instanceOf2 = new Subclass2();

System.debug('Class 1: ' + instanceOf1.myMethod());  // Expected: Superclass1
System.debug('Class 2: ' + instanceOf2.myMethod());  // Expected: Superclass1 (not Subclass2)

Now, the output is:

Class 1: Superclass1
Class 2: Superclass1

In version 61.0, Salesforce no longer calls Subclass2‘s myMethod(). Instead, it calls Superclass1‘s myMethod() because the private method in Superclass1 isn’t being overridden by the subclass method.

Why Does This Happen?

The key change is that private methods are no longer inherited or overridden in subclasses in API version 61.0. This means that any attempt to override a private method in a subclass will not work as expected. The method in the superclass remains the one that gets called, regardless of any subclass method with the same signature.

This change was made as part of a broader effort to make the behavior of private methods more predictable and less prone to unintentional inheritance. It strengthens the encapsulation of private methods, ensuring that they cannot be accessed or altered by subclasses.

How to Fix This?

If you encounter this behavior after upgrading to API version 61.0, the fix is relatively simple. You need to change the visibility of the method in the superclass from private to a higher visibility level like protected or public. By doing this, the method in the superclass becomes accessible and overrideable in subclasses, which will restore the expected polymorphic behavior.

For example, you could modify the superclass method like this:

public class Superclass1 {
    protected virtual String myMethod() {
        return 'Superclass1';
    }
}

Now, the method in Subclass2 can correctly override myMethod() from Superclass1, and polymorphism will work as expected. This approach resolves the issue while keeping the desired behavior intact.

Why Did Salesforce Make This Change?

Salesforce likely made this change to improve consistency, security, and maintainability in Apex. By restricting the overriding of private methods, they ensure that the internal logic of a class cannot be accidentally altered or accessed through inheritance, which is a common problem in object-oriented design.

In summary, while the behavior you’re experiencing may initially seem like a bug, it’s actually a change that was deliberately introduced in API version 61.0 to enhance the way private methods are handled in inheritance scenarios. If this affects your code, adjusting the method visibility as described above should resolve the issue.

Real-Time Project-Based Salesforce Training to Kick Start Your Career

Our Salesforce Course is designed to offer a comprehensive understanding of the Salesforce platform, providing you with the essential skills needed to excel in the CRM industry. The program covers key modules like Salesforce Admin, Developer, and AI, blending theoretical concepts with hands-on experience. Through real-world projects and interactive assignments, you will gain the expertise to tackle business challenges using Salesforce solutions. Our expert trainers ensure you acquire both technical proficiency and industry knowledge to thrive in the Salesforce ecosystem.

Beyond technical learning, our Salesforce Training in Boston includes personalized mentorship, certification support, and interview preparation to boost your career prospects. You will have access to extensive study resources, practical project experience, and continuous guidance throughout your training. By the end of the course, you will be fully prepared for certification exams and equipped with real-world problem-solving skills that employers seek. Take the first step in your Salesforce journey with us and unlock limitless career opportunities. Sign up for a Free Demo today!

Comments are closed.