An object in C# may have functions that are actually a composite of different categories; a classic example of this is the Teacher example:

In this example, the Teacher has the characteristics of a Person (e.g. Eye Colour) (although I've had some teachers that may break this example) and the characteristics of an Employee (e.g. Salary)
C# doesn't allow for multiple inheritance so instead we look to the idea of composition using interfaces. It is often described this way:
Inheritance implies that if Cat inherits from Animal then Cat "is-a" Animal
Composition implies that if Cat implements Noise then Cat "has-a" Noise
Why is this distinction important? Well, imagine our Cat. We could actually have Cat inherit from Feline, which in turn inherits from Animal. One day, we decide that we are going to support other types of Animal, so we decide to revise Animal, but then we realise that we are going to be pushing these changes to every other sub type. Our design, and hierarchy is suddenly quite complicated, and, if we didn't get it right to begin with, we have to extensively redesign all of our child classes.
A rule is to Prefer Composition over Inheritance , but note the use of the word Prefer - it's important, because it doesn't mean that we should just use composition, but instead, our design should consider when inheritance is useful and when composition is useful too. It also reminds us that sticking every possible method ever in the base class is a bad idea.
I like your shape example. Consider:

Our ShapeSorter might have a method like this:
public bool Sort(Shape shape)
{
foreach(Hole hole in Holes)
{
if(Hole.Type == HoleType.Circular && shape is Circle)
{
return true;
}
if(Hole.Type == HoleType.Square && shape is Square)
{
return true;
}
if(Hole.Type == HoleType.Triangular && shape is Triangle)
{
return true;
}
}
return false;
}
Or, we could do some slight inversion of control:
public bool Sort(Shape shape, Hole hole)
{
return hole.Accepts(shape); //We end up pushing the `if` code into Hole
}
Or some variant thereof. We are already writing a lot of code that relies on us knowing the exact sort of Shape. Imagine how tedious it gets to maintain when you have one of these:

So, instead, we think to ourselves - is there a more generic way we can describe our problem by distilling it down to the relevant properties?
You've called it IShape:
public interface IShape{
double Area {get;}
double Perimeter { get; } //Prefer Perimeter over circumference as more applicable to other shapes
int Sides { get; }
HoleType ShapeType { get; }
}
Our Sort method would then become:
public Hole Sort(IShape shape)
{
foreach(Hole hole in Holes)
{
if(hole.HoleType == shape.ShapeType && hole.Area >= shape.Area)
{
return hole;
}
}
return null;
}
Which looks neater, but isn't really anything that couldn't have been done via Shape directly.
The truth is that there is no truth. The most common approach will involve using both inheritance and composition, as many things in the real world will be both of a type and will also have other attributes best described by an interface. The most important thing to avoid is sticking every possible method in the base class and having huge if statements to work out what the derived types can and can't do - this is a lot of code that is hard to maintain. Also, putting too much functionality in base classes can lead to setting your code in concrete - you wont want to revise things later because of all the potential side effects.