The virtual keyword is used to define a method, property, or indexer in a base class, allowing it to be overridden in derived classes. This concept is known as method overriding, and it is a fundamental feature of object-oriented programming, enabling polymorphism and providing flexibility in class hierarchies.
Usage of the virtual keyword:
To create a virtual method, you use the virtual keyword in the method declaration within the base class. This allows derived classes to provide their own implementation of the method. 
public class Shape
{
    public virtual void Draw()
    {
        Console.WriteLine("Drawing a shape.");
    }
}
public class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a circle.");
    }
}
public class Square : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a square.");
    }
}
In this example, the Draw method in the Shape class is marked as virtual, allowing it to be overridden in the Circle and Square classes.
Similarly, you can define a virtual property using the virtual keyword in the base class. Derived classes can then provide their own implementation of the property. 
public class Animal
{
    public virtual string Sound { get; set; } = "Unknown";
}
public class Dog : Animal
{
    public override string Sound => "Woof";
}
public class Cat : Animal
{
    public override string Sound => "Meow";
}
In this example, the Sound property in the Animal class is marked as virtual, allowing Dog and Cat classes to override it and provide custom implementations.
You can also define virtual indexers in the same way, allowing derived classes to have their own indexers. 
public class Collection
{
    public virtual int this[int index]
    {
        get { /* Implementation */ }
        set { /* Implementation */ }
    }
}
public class DerivedCollection : Collection
{
    public override int this[int index]
    {
        get { /* Derived implementation */ }
        set { /* Derived implementation */ }
    }
}
Using the virtual keyword allows for method overriding, enabling classes to provide their own behavior while still adhering to a common interface defined in the base class. This flexibility and polymorphism are crucial for building modular and extensible object-oriented systems.