I am still years away from fully grasping the distinction between an abstract class and an interface. Every time I think I get a handle on the basic concepts, I go looking on stackexchange and I'm two steps back. But a few thoughts on the topic and the OPs question:
First:
There are two common explanations of an interface:
An interface is a list of methods and properties that any class can implement, and by implementing an interface, a class guarantees those methods (and their signatures) and those properties (and their types) will be available when "interfacing" with that class or an object of that class. An interface is a contract.
Interfaces are abstract classes that don't/can't do anything. They're useful because you can implement more than one, unlike those mean parent classes. Like, I could be an object of class BananaBread, and inherit from BaseBread, but that doesn't mean I can't also implement both the IWithNuts and the ITastesYummy interfaces. I could even implement the IDoesTheDishes interface, because I'm not just bread, yknow?
There are two common explanations of an abstract class:
An abstract class is, yknow, the thing not what the thing can do. It's like, the essence, not really a real thing at all. Hang on, this will help. A boat is an abstract class, but a sexy Playboy Yacht would be a sub class of BaseBoat.
I read a book on abstract classes, and maybe you should read that book, because you probably don't get it and will do it wrong if you haven't read that book.
By the way, the book Citers always seem impressive, even if I still walk away confused.
Second:
On SO, someone asked a simpler version of this question, the classic, "why use interfaces? What's the difference? What am I missing?" And one answer used an air force pilot as a simple example. It didn't quite land, but it sparked some great comments, one of which mentioned the IFlyable interface having methods like takeOff, pilotEject, etc. And this really clicked for me as a real-world example of why interfaces are not just useful, but crucial. An interface makes an object/class intuitive, or at least gives the sense that it is. An interface isn't for the benefit of the object or the data, but for something that needs to interact with that object. The classic Fruit->Apple->Fuji or Shape->Triangle->Equilateral examples of inheritance are a great model for taxonomically understanding a given object based on its descendants. It informs the consumer and the processors about its general qualities, behaviors, whether the object is a group of things, will hose your system if you put it in the wrong place, or describes sensory data, a connector to a specific data store, or financial data needed to make payroll.
A specific Plane object may or may not have a method for an emergency landing, but I'm going to be pissed off if I assume its emergencyLand like every other flyable object only to wake up covered in DumbPlane and learn that the developers went with quickLand because they thought that it was all the same. Just like how I would be frustrated if every screw manufacturer had their own interpretation of righty tighty or if my TV didn't have the volume increase button above the volume decrease button.
Abstract classes are the model that establishes what any descendent object must have to qualifiy as that class. If you don't have all the qualities of a duck, it doesn't matter that you have the IQuack interface implemented, your just a weird penguin. Interfaces are the things that make sense even when you can't be sure of anything else. Jeff Goldblum and Starbuck were both able to fly alien spaceships because the interface was reliably similar.
Third:
I agree with your coworker, because sometimes you need to enforce certain methods at the very start. If you're creating an Active Record ORM, it needs a save method. This isn't up to the subclass that can be instantiated. And if the ICRUD interface is portable enough to not be exclusively coupled to the one abstract class, it can be implemented by other classes to make them reliable and intuitive for anyone already familiar with any of the descendant classes of that abstract class.
On the other hand, there was a great example earlier of when to not jump to tying an interface to the abstract class, because not all list types will (or should) implement a queue interface. You said this scenario happens half the time, which means you and your coworker are both wrong half the time, and thus the best thing to do is argue, debate, consider, and if they turn out to be right, acknowledge and accept the coupling. But don't become a developer who follows a philosophy even when it isn't not the best one for the job at hand.
Work
is the diamond inheritance issue (in that case they both fulfill a contract over theWork
method). In Java you're required to implement the interface's methods so the issue of whichWork
method the program should use is avoided in that way. Languages such as C++ however doesn't disambiguate this for you.