Skip to main content

How to Resolve Error "CS0621: 'member' : virtual or abstract members cannot be private" in C#

The Compiler Error CS0621 is an Object-Oriented Design error. The message reads: "'MemberName' : virtual or abstract members cannot be private".

In C#, the keywords virtual and abstract are invitations for derived classes (children) to modify or supply implementation logic. The keyword private restricts access strictly to the containing class, making the member invisible to derived classes.

These two concepts are mutually exclusive. You cannot ask a child class to override a method that it cannot see.

This guide explains the rules of polymorphism visibility and how to fix this contradiction.

Understanding Polymorphism and Access

  • virtual / abstract: Intended to be accessed and modified by Derived Classes.
  • private: Intended to be hidden from Everyone (including Derived Classes).

If a member is private, the derived class does not know it exists. Therefore, the runtime cannot dispatch calls to the derived class's implementation, rendering the virtual or abstract keyword useless.

Scenario 1: Private Virtual Methods

You might try to create a helper method that has a default implementation but can be customized, while trying to keep it hidden from the outside world.

Example of error:

public class BaseClass
{
// ⛔️ Error CS0621: 'Log' : virtual or abstract members cannot be private.
// The intention is "Let children change this", but 'private' says "Children keep out".
private virtual void Log(string message)
{
Console.WriteLine($"Base: {message}");
}
}

Scenario 2: Private Abstract Methods

This scenario is even more contradictory. An abstract method must be overridden by the derived class. If it is private, the derived class cannot see it to override it, making it impossible to compile a valid concrete class.

Example of error:

public abstract class Animal
{
// ⛔️ Error CS0621: abstract members cannot be private.
// Derived classes are REQUIRED to implement this, but they aren't ALLOWED to see it.
private abstract void MakeSound();
}

Solution: Use protected or public

To resolve this, you must increase the visibility of the member.

If you want the method to be hidden from the "outside world" (like Main or other classes) but visible to derived classes for overriding, use protected.

public class BaseClass
{
// ✅ Correct: 'protected' allows children to see and override it,
// but keeps it private from the rest of the world.
protected virtual void Log(string message)
{
Console.WriteLine($"Base: {message}");
}
}

public class ChildClass : BaseClass
{
protected override void Log(string message)
{
Console.WriteLine($"Child: {message}");
}
}

Option B: Use public (For API surfaces)

If the method is part of the public interface of your class, use public.

public abstract class Animal
{
// ✅ Correct: Everyone can see this, and children must implement it.
public abstract void MakeSound();
}

Option C: Remove virtual (If strictly private)

If the method truly must be private, then it cannot be polymorphic. Remove the virtual keyword.

public class BaseClass
{
// ✅ Correct: It is private, but it is no longer virtual.
// Child classes cannot override this.
private void Log(string message)
{
Console.WriteLine(message);
}
}
note

Access Level Rules for Overriding: When you override a method, the access level must match.

  • protected virtual -> must be overridden by protected override.
  • public virtual -> must be overridden by public override.

Conclusion

CS0621 acts as a logic check for your architecture.

  1. Identify the Goal: Do you want derived classes to change this behavior?
    • Yes: Change private to protected (restricted) or public (open).
    • No: Remove the virtual or abstract keyword and keep it private.